OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [encoding/] [pem/] [pem.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2009 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
 
5
// Package pem implements the PEM data encoding, which originated in Privacy
6
// Enhanced Mail. The most common use of PEM encoding today is in TLS keys and
7
// certificates. See RFC 1421.
8
package pem
9
 
10
import (
11
        "bytes"
12
        "encoding/base64"
13
        "io"
14
)
15
 
16
// A Block represents a PEM encoded structure.
17
//
18
// The encoded form is:
19
//    -----BEGIN Type-----
20
//    Headers
21
//    base64-encoded Bytes
22
//    -----END Type-----
23
// where Headers is a possibly empty sequence of Key: Value lines.
24
type Block struct {
25
        Type    string            // The type, taken from the preamble (i.e. "RSA PRIVATE KEY").
26
        Headers map[string]string // Optional headers.
27
        Bytes   []byte            // The decoded bytes of the contents. Typically a DER encoded ASN.1 structure.
28
}
29
 
30
// getLine results the first \r\n or \n delineated line from the given byte
31
// array. The line does not include the \r\n or \n. The remainder of the byte
32
// array (also not including the new line bytes) is also returned and this will
33
// always be smaller than the original argument.
34
func getLine(data []byte) (line, rest []byte) {
35
        i := bytes.Index(data, []byte{'\n'})
36
        var j int
37
        if i < 0 {
38
                i = len(data)
39
                j = i
40
        } else {
41
                j = i + 1
42
                if i > 0 && data[i-1] == '\r' {
43
                        i--
44
                }
45
        }
46
        return data[0:i], data[j:]
47
}
48
 
49
// removeWhitespace returns a copy of its input with all spaces, tab and
50
// newline characters removed.
51
func removeWhitespace(data []byte) []byte {
52
        result := make([]byte, len(data))
53
        n := 0
54
 
55
        for _, b := range data {
56
                if b == ' ' || b == '\t' || b == '\r' || b == '\n' {
57
                        continue
58
                }
59
                result[n] = b
60
                n++
61
        }
62
 
63
        return result[0:n]
64
}
65
 
66
var pemStart = []byte("\n-----BEGIN ")
67
var pemEnd = []byte("\n-----END ")
68
var pemEndOfLine = []byte("-----")
69
 
70
// Decode will find the next PEM formatted block (certificate, private key
71
// etc) in the input. It returns that block and the remainder of the input. If
72
// no PEM data is found, p is nil and the whole of the input is returned in
73
// rest.
74
func Decode(data []byte) (p *Block, rest []byte) {
75
        // pemStart begins with a newline. However, at the very beginning of
76
        // the byte array, we'll accept the start string without it.
77
        rest = data
78
        if bytes.HasPrefix(data, pemStart[1:]) {
79
                rest = rest[len(pemStart)-1 : len(data)]
80
        } else if i := bytes.Index(data, pemStart); i >= 0 {
81
                rest = rest[i+len(pemStart) : len(data)]
82
        } else {
83
                return nil, data
84
        }
85
 
86
        typeLine, rest := getLine(rest)
87
        if !bytes.HasSuffix(typeLine, pemEndOfLine) {
88
                return decodeError(data, rest)
89
        }
90
        typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)]
91
 
92
        p = &Block{
93
                Headers: make(map[string]string),
94
                Type:    string(typeLine),
95
        }
96
 
97
        for {
98
                // This loop terminates because getLine's second result is
99
                // always smaller than its argument.
100
                if len(rest) == 0 {
101
                        return nil, data
102
                }
103
                line, next := getLine(rest)
104
 
105
                i := bytes.Index(line, []byte{':'})
106
                if i == -1 {
107
                        break
108
                }
109
 
110
                // TODO(agl): need to cope with values that spread across lines.
111
                key, val := line[0:i], line[i+1:]
112
                key = bytes.TrimSpace(key)
113
                val = bytes.TrimSpace(val)
114
                p.Headers[string(key)] = string(val)
115
                rest = next
116
        }
117
 
118
        i := bytes.Index(rest, pemEnd)
119
        if i < 0 {
120
                return decodeError(data, rest)
121
        }
122
        base64Data := removeWhitespace(rest[0:i])
123
 
124
        p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
125
        n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
126
        if err != nil {
127
                return decodeError(data, rest)
128
        }
129
        p.Bytes = p.Bytes[0:n]
130
 
131
        _, rest = getLine(rest[i+len(pemEnd):])
132
 
133
        return
134
}
135
 
136
func decodeError(data, rest []byte) (*Block, []byte) {
137
        // If we get here then we have rejected a likely looking, but
138
        // ultimately invalid PEM block. We need to start over from a new
139
        // position.  We have consumed the preamble line and will have consumed
140
        // any lines which could be header lines. However, a valid preamble
141
        // line is not a valid header line, therefore we cannot have consumed
142
        // the preamble line for the any subsequent block. Thus, we will always
143
        // find any valid block, no matter what bytes precede it.
144
        //
145
        // For example, if the input is
146
        //
147
        //    -----BEGIN MALFORMED BLOCK-----
148
        //    junk that may look like header lines
149
        //   or data lines, but no END line
150
        //
151
        //    -----BEGIN ACTUAL BLOCK-----
152
        //    realdata
153
        //    -----END ACTUAL BLOCK-----
154
        //
155
        // we've failed to parse using the first BEGIN line
156
        // and now will try again, using the second BEGIN line.
157
        p, rest := Decode(rest)
158
        if p == nil {
159
                rest = data
160
        }
161
        return p, rest
162
}
163
 
164
const pemLineLength = 64
165
 
166
type lineBreaker struct {
167
        line [pemLineLength]byte
168
        used int
169
        out  io.Writer
170
}
171
 
172
func (l *lineBreaker) Write(b []byte) (n int, err error) {
173
        if l.used+len(b) < pemLineLength {
174
                copy(l.line[l.used:], b)
175
                l.used += len(b)
176
                return len(b), nil
177
        }
178
 
179
        n, err = l.out.Write(l.line[0:l.used])
180
        if err != nil {
181
                return
182
        }
183
        excess := pemLineLength - l.used
184
        l.used = 0
185
 
186
        n, err = l.out.Write(b[0:excess])
187
        if err != nil {
188
                return
189
        }
190
 
191
        n, err = l.out.Write([]byte{'\n'})
192
        if err != nil {
193
                return
194
        }
195
 
196
        return l.Write(b[excess:])
197
}
198
 
199
func (l *lineBreaker) Close() (err error) {
200
        if l.used > 0 {
201
                _, err = l.out.Write(l.line[0:l.used])
202
                if err != nil {
203
                        return
204
                }
205
                _, err = l.out.Write([]byte{'\n'})
206
        }
207
 
208
        return
209
}
210
 
211
func Encode(out io.Writer, b *Block) (err error) {
212
        _, err = out.Write(pemStart[1:])
213
        if err != nil {
214
                return
215
        }
216
        _, err = out.Write([]byte(b.Type + "-----\n"))
217
        if err != nil {
218
                return
219
        }
220
 
221
        if len(b.Headers) > 0 {
222
                for k, v := range b.Headers {
223
                        _, err = out.Write([]byte(k + ": " + v + "\n"))
224
                        if err != nil {
225
                                return
226
                        }
227
                }
228
                _, err = out.Write([]byte{'\n'})
229
                if err != nil {
230
                        return
231
                }
232
        }
233
 
234
        var breaker lineBreaker
235
        breaker.out = out
236
 
237
        b64 := base64.NewEncoder(base64.StdEncoding, &breaker)
238
        _, err = b64.Write(b.Bytes)
239
        if err != nil {
240
                return
241
        }
242
        b64.Close()
243
        breaker.Close()
244
 
245
        _, err = out.Write(pemEnd[1:])
246
        if err != nil {
247
                return
248
        }
249
        _, err = out.Write([]byte(b.Type + "-----\n"))
250
        return
251
}
252
 
253
func EncodeToMemory(b *Block) []byte {
254
        var buf bytes.Buffer
255
        Encode(&buf, b)
256
        return buf.Bytes()
257
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.