1 /* Copyright (C) 2007 The Written Word, Inc.
2 * Copyright (C) 2008, Simon Josefsson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms,
6 * with or without modification, are permitted provided
7 * that the following conditions are met:
8 *
9 * Redistributions of source code must retain the above
10 * copyright notice, this list of conditions and the
11 * following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials
16 * provided with the distribution.
17 *
18 * Neither the name of the copyright holder nor the names
19 * of any other contributors may be used to endorse or
20 * promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
35 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
36 * OF SUCH DAMAGE.
37 */
38
39 #include "libssh2_priv.h"
40
41 static int
readline(char * line,int line_size,FILE * fp)42 readline(char *line, int line_size, FILE * fp)
43 {
44 size_t len;
45
46 if (!line) {
47 return -1;
48 }
49 if (!fgets(line, line_size, fp)) {
50 return -1;
51 }
52
53 if (*line) {
54 len = strlen(line);
55 if (len > 0 && line[len - 1] == '\n') {
56 line[len - 1] = '\0';
57 }
58 }
59
60 if (*line) {
61 len = strlen(line);
62 if (len > 0 && line[len - 1] == '\r') {
63 line[len - 1] = '\0';
64 }
65 }
66
67 return 0;
68 }
69
70 static int
readline_memory(char * line,size_t line_size,const char * filedata,size_t filedata_len,size_t * filedata_offset)71 readline_memory(char *line, size_t line_size,
72 const char *filedata, size_t filedata_len,
73 size_t *filedata_offset)
74 {
75 size_t off, len;
76
77 off = *filedata_offset;
78
79 for (len = 0; off + len < filedata_len && len < line_size; len++) {
80 if (filedata[off + len] == '\n' ||
81 filedata[off + len] == '\r') {
82 break;
83 }
84 }
85
86 if (len) {
87 memcpy(line, filedata + off, len);
88 *filedata_offset += len;
89 }
90
91 line[len] = '\0';
92 *filedata_offset += 1;
93
94 return 0;
95 }
96
97 #define LINE_SIZE 128
98
99 int
_libssh2_pem_parse(LIBSSH2_SESSION * session,const char * headerbegin,const char * headerend,FILE * fp,unsigned char ** data,unsigned int * datalen)100 _libssh2_pem_parse(LIBSSH2_SESSION * session,
101 const char *headerbegin,
102 const char *headerend,
103 FILE * fp, unsigned char **data, unsigned int *datalen)
104 {
105 char line[LINE_SIZE];
106 char *b64data = NULL;
107 unsigned int b64datalen = 0;
108 int ret;
109
110 do {
111 *line = '\0';
112
113 if (readline(line, LINE_SIZE, fp)) {
114 return -1;
115 }
116 }
117 while (strcmp(line, headerbegin) != 0);
118
119 *line = '\0';
120
121 do {
122 if (*line) {
123 char *tmp;
124 size_t linelen;
125
126 linelen = strlen(line);
127 tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
128 if (!tmp) {
129 ret = -1;
130 goto out;
131 }
132 memcpy(tmp + b64datalen, line, linelen);
133 b64data = tmp;
134 b64datalen += linelen;
135 }
136
137 *line = '\0';
138
139 if (readline(line, LINE_SIZE, fp)) {
140 ret = -1;
141 goto out;
142 }
143 } while (strcmp(line, headerend) != 0);
144
145 if (!b64data) {
146 return -1;
147 }
148
149 if (libssh2_base64_decode(session, (char**) data, datalen,
150 b64data, b64datalen)) {
151 ret = -1;
152 goto out;
153 }
154
155 ret = 0;
156 out:
157 if (b64data) {
158 LIBSSH2_FREE(session, b64data);
159 }
160 return ret;
161 }
162
163 int
_libssh2_pem_parse_memory(LIBSSH2_SESSION * session,const char * headerbegin,const char * headerend,const char * filedata,size_t filedata_len,unsigned char ** data,unsigned int * datalen)164 _libssh2_pem_parse_memory(LIBSSH2_SESSION * session,
165 const char *headerbegin,
166 const char *headerend,
167 const char *filedata, size_t filedata_len,
168 unsigned char **data, unsigned int *datalen)
169 {
170 char line[LINE_SIZE];
171 char *b64data = NULL;
172 unsigned int b64datalen = 0;
173 size_t off = 0;
174 int ret;
175
176 do {
177 *line = '\0';
178
179 if (readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
180 return -1;
181 }
182 }
183 while (strcmp(line, headerbegin) != 0);
184
185 *line = '\0';
186
187 do {
188 if (*line) {
189 char *tmp;
190 size_t linelen;
191
192 linelen = strlen(line);
193 tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
194 if (!tmp) {
195 ret = -1;
196 goto out;
197 }
198 memcpy(tmp + b64datalen, line, linelen);
199 b64data = tmp;
200 b64datalen += linelen;
201 }
202
203 *line = '\0';
204
205 if (readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
206 ret = -1;
207 goto out;
208 }
209 } while (strcmp(line, headerend) != 0);
210
211 if (!b64data) {
212 return -1;
213 }
214
215 if (libssh2_base64_decode(session, (char**) data, datalen,
216 b64data, b64datalen)) {
217 ret = -1;
218 goto out;
219 }
220
221 ret = 0;
222 out:
223 if (b64data) {
224 LIBSSH2_FREE(session, b64data);
225 }
226 return ret;
227 }
228
229 static int
read_asn1_length(const unsigned char * data,unsigned int datalen,unsigned int * len)230 read_asn1_length(const unsigned char *data,
231 unsigned int datalen, unsigned int *len)
232 {
233 unsigned int lenlen;
234 int nextpos;
235
236 if (datalen < 1) {
237 return -1;
238 }
239 *len = data[0];
240
241 if (*len >= 0x80) {
242 lenlen = *len & 0x7F;
243 *len = data[1];
244 if (1 + lenlen > datalen) {
245 return -1;
246 }
247 if (lenlen > 1) {
248 *len <<= 8;
249 *len |= data[2];
250 }
251 } else {
252 lenlen = 0;
253 }
254
255 nextpos = 1 + lenlen;
256 if (lenlen > 2 || 1 + lenlen + *len > datalen) {
257 return -1;
258 }
259
260 return nextpos;
261 }
262
263 int
_libssh2_pem_decode_sequence(unsigned char ** data,unsigned int * datalen)264 _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen)
265 {
266 unsigned int len;
267 int lenlen;
268
269 if (*datalen < 1) {
270 return -1;
271 }
272
273 if ((*data)[0] != '\x30') {
274 return -1;
275 }
276
277 (*data)++;
278 (*datalen)--;
279
280 lenlen = read_asn1_length(*data, *datalen, &len);
281 if (lenlen < 0 || lenlen + len != *datalen) {
282 return -1;
283 }
284
285 *data += lenlen;
286 *datalen -= lenlen;
287
288 return 0;
289 }
290
291 int
_libssh2_pem_decode_integer(unsigned char ** data,unsigned int * datalen,unsigned char ** i,unsigned int * ilen)292 _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
293 unsigned char **i, unsigned int *ilen)
294 {
295 unsigned int len;
296 int lenlen;
297
298 if (*datalen < 1) {
299 return -1;
300 }
301
302 if ((*data)[0] != '\x02') {
303 return -1;
304 }
305
306 (*data)++;
307 (*datalen)--;
308
309 lenlen = read_asn1_length(*data, *datalen, &len);
310 if (lenlen < 0 || lenlen + len > *datalen) {
311 return -1;
312 }
313
314 *data += lenlen;
315 *datalen -= lenlen;
316
317 *i = *data;
318 *ilen = len;
319
320 *data += len;
321 *datalen -= len;
322
323 return 0;
324 }
325