@@ -90,122 +90,96 @@ func Decode(data []byte) (p *Block, rest []byte) {
90
90
// pemStart begins with a newline. However, at the very beginning of
91
91
// the byte array, we'll accept the start string without it.
92
92
rest = data
93
- if bytes .HasPrefix (data , pemStart [1 :]) {
94
- rest = rest [len (pemStart )- 1 : len (data )]
95
- } else if _ , after , ok := bytes .Cut (data , pemStart ); ok {
96
- rest = after
97
- } else {
98
- return nil , data
99
- }
100
-
101
- typeLine , rest := getLine (rest )
102
- if ! bytes .HasSuffix (typeLine , pemEndOfLine ) {
103
- return decodeError (data , rest )
104
- }
105
- typeLine = typeLine [0 : len (typeLine )- len (pemEndOfLine )]
106
-
107
- p = & Block {
108
- Headers : make (map [string ]string ),
109
- Type : string (typeLine ),
110
- }
111
-
112
93
for {
113
- // This loop terminates because getLine's second result is
114
- // always smaller than its argument.
115
- if len (rest ) == 0 {
94
+ if bytes .HasPrefix (rest , pemStart [1 :]) {
95
+ rest = rest [len (pemStart )- 1 :]
96
+ } else if _ , after , ok := bytes .Cut (rest , pemStart ); ok {
97
+ rest = after
98
+ } else {
116
99
return nil , data
117
100
}
118
- line , next := getLine (rest )
119
101
120
- key , val , ok := bytes .Cut (line , colon )
121
- if ! ok {
122
- break
102
+ var typeLine []byte
103
+ typeLine , rest = getLine (rest )
104
+ if ! bytes .HasSuffix (typeLine , pemEndOfLine ) {
105
+ continue
123
106
}
107
+ typeLine = typeLine [0 : len (typeLine )- len (pemEndOfLine )]
124
108
125
- // TODO(agl): need to cope with values that spread across lines.
126
- key = bytes .TrimSpace (key )
127
- val = bytes .TrimSpace (val )
128
- p .Headers [string (key )] = string (val )
129
- rest = next
130
- }
109
+ p = & Block {
110
+ Headers : make (map [string ]string ),
111
+ Type : string (typeLine ),
112
+ }
131
113
132
- var endIndex , endTrailerIndex int
114
+ for {
115
+ // This loop terminates because getLine's second result is
116
+ // always smaller than its argument.
117
+ if len (rest ) == 0 {
118
+ return nil , data
119
+ }
120
+ line , next := getLine (rest )
133
121
134
- // If there were no headers, the END line might occur
135
- // immediately, without a leading newline.
136
- if len (p .Headers ) == 0 && bytes .HasPrefix (rest , pemEnd [1 :]) {
137
- endIndex = 0
138
- endTrailerIndex = len (pemEnd ) - 1
139
- } else {
140
- endIndex = bytes .Index (rest , pemEnd )
141
- endTrailerIndex = endIndex + len (pemEnd )
142
- }
122
+ key , val , ok := bytes .Cut (line , colon )
123
+ if ! ok {
124
+ break
125
+ }
143
126
144
- if endIndex < 0 {
145
- return decodeError (data , rest )
146
- }
127
+ // TODO(agl): need to cope with values that spread across lines.
128
+ key = bytes .TrimSpace (key )
129
+ val = bytes .TrimSpace (val )
130
+ p .Headers [string (key )] = string (val )
131
+ rest = next
132
+ }
147
133
148
- // After the "-----" of the ending line, there should be the same type
149
- // and then a final five dashes.
150
- endTrailer := rest [endTrailerIndex :]
151
- endTrailerLen := len (typeLine ) + len (pemEndOfLine )
152
- if len (endTrailer ) < endTrailerLen {
153
- return decodeError (data , rest )
154
- }
134
+ var endIndex , endTrailerIndex int
155
135
156
- restOfEndLine := endTrailer [endTrailerLen :]
157
- endTrailer = endTrailer [:endTrailerLen ]
158
- if ! bytes .HasPrefix (endTrailer , typeLine ) ||
159
- ! bytes .HasSuffix (endTrailer , pemEndOfLine ) {
160
- return decodeError (data , rest )
161
- }
136
+ // If there were no headers, the END line might occur
137
+ // immediately, without a leading newline.
138
+ if len (p .Headers ) == 0 && bytes .HasPrefix (rest , pemEnd [1 :]) {
139
+ endIndex = 0
140
+ endTrailerIndex = len (pemEnd ) - 1
141
+ } else {
142
+ endIndex = bytes .Index (rest , pemEnd )
143
+ endTrailerIndex = endIndex + len (pemEnd )
144
+ }
162
145
163
- // The line must end with only whitespace.
164
- if s , _ := getLine (restOfEndLine ); len (s ) != 0 {
165
- return decodeError (data , rest )
166
- }
146
+ if endIndex < 0 {
147
+ continue
148
+ }
167
149
168
- base64Data := removeSpacesAndTabs (rest [:endIndex ])
169
- p .Bytes = make ([]byte , base64 .StdEncoding .DecodedLen (len (base64Data )))
170
- n , err := base64 .StdEncoding .Decode (p .Bytes , base64Data )
171
- if err != nil {
172
- return decodeError (data , rest )
173
- }
174
- p .Bytes = p .Bytes [:n ]
150
+ // After the "-----" of the ending line, there should be the same type
151
+ // and then a final five dashes.
152
+ endTrailer := rest [endTrailerIndex :]
153
+ endTrailerLen := len (typeLine ) + len (pemEndOfLine )
154
+ if len (endTrailer ) < endTrailerLen {
155
+ continue
156
+ }
157
+
158
+ restOfEndLine := endTrailer [endTrailerLen :]
159
+ endTrailer = endTrailer [:endTrailerLen ]
160
+ if ! bytes .HasPrefix (endTrailer , typeLine ) ||
161
+ ! bytes .HasSuffix (endTrailer , pemEndOfLine ) {
162
+ continue
163
+ }
175
164
176
- // the -1 is because we might have only matched pemEnd without the
177
- // leading newline if the PEM block was empty.
178
- _ , rest = getLine (rest [endIndex + len (pemEnd )- 1 :])
165
+ // The line must end with only whitespace.
166
+ if s , _ := getLine (restOfEndLine ); len (s ) != 0 {
167
+ continue
168
+ }
179
169
180
- return
181
- }
170
+ base64Data := removeSpacesAndTabs (rest [:endIndex ])
171
+ p .Bytes = make ([]byte , base64 .StdEncoding .DecodedLen (len (base64Data )))
172
+ n , err := base64 .StdEncoding .Decode (p .Bytes , base64Data )
173
+ if err != nil {
174
+ continue
175
+ }
176
+ p .Bytes = p .Bytes [:n ]
182
177
183
- func decodeError (data , rest []byte ) (* Block , []byte ) {
184
- // If we get here then we have rejected a likely looking, but
185
- // ultimately invalid PEM block. We need to start over from a new
186
- // position. We have consumed the preamble line and will have consumed
187
- // any lines which could be header lines. However, a valid preamble
188
- // line is not a valid header line, therefore we cannot have consumed
189
- // the preamble line for the any subsequent block. Thus, we will always
190
- // find any valid block, no matter what bytes precede it.
191
- //
192
- // For example, if the input is
193
- //
194
- // -----BEGIN MALFORMED BLOCK-----
195
- // junk that may look like header lines
196
- // or data lines, but no END line
197
- //
198
- // -----BEGIN ACTUAL BLOCK-----
199
- // realdata
200
- // -----END ACTUAL BLOCK-----
201
- //
202
- // we've failed to parse using the first BEGIN line
203
- // and now will try again, using the second BEGIN line.
204
- p , rest := Decode (rest )
205
- if p == nil {
206
- rest = data
178
+ // the -1 is because we might have only matched pemEnd without the
179
+ // leading newline if the PEM block was empty.
180
+ _ , rest = getLine (rest [endIndex + len (pemEnd )- 1 :])
181
+ return p , rest
207
182
}
208
- return p , rest
209
183
}
210
184
211
185
const pemLineLength = 64
0 commit comments