]>
git.ipfire.org Git - people/ms/strongswan.git/blob - Source/lib/asn1-pluto/pem.c
24c71c61fb64191a3074fa1d2d7cb3547f7835a7
2 * Copyright (C) 2005 Jan Hutter, Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 #include <sys/types.h>
27 #include <crypto/hashers/hasher.h>
28 #include <crypto/crypters/crypter.h>
32 * check the presence of a pattern in a character string
34 static bool present(const char* pattern
, chunk_t
* ch
)
36 u_int pattern_len
= strlen(pattern
);
38 if (ch
->len
>= pattern_len
&& strncmp(ch
->ptr
, pattern
, pattern_len
) == 0)
40 ch
->ptr
+= pattern_len
;
41 ch
->len
-= pattern_len
;
48 * compare string with chunk
50 static bool match(const char *pattern
, const chunk_t
*ch
)
52 return ch
->len
== strlen(pattern
) && strncmp(pattern
, ch
->ptr
, ch
->len
) == 0;
56 * find a boundary of the form -----tag name-----
58 static bool find_boundary(const char* tag
, chunk_t
*line
)
60 chunk_t name
= CHUNK_INITIALIZER
;
62 if (!present("-----", line
))
64 if (!present(tag
, line
))
66 if (*line
->ptr
!= ' ')
68 line
->ptr
++; line
->len
--;
74 if (present("-----", line
))
78 line
->ptr
++; line
->len
--; name
.len
++;
86 static void eat_whitespace(chunk_t
*src
)
88 while (src
->len
> 0 && (*src
->ptr
== ' ' || *src
->ptr
== '\t'))
90 src
->ptr
++; src
->len
--;
95 * extracts a token ending with a given termination symbol
97 static bool extract_token(chunk_t
*token
, char termination
, chunk_t
*src
)
99 u_char
*eot
= memchr(src
->ptr
, termination
, src
->len
);
101 /* initialize empty token */
102 *token
= CHUNK_INITIALIZER
;
104 if (eot
== NULL
) /* termination symbol not found */
110 token
->ptr
= src
->ptr
;
111 token
->len
= (u_int
)(eot
- src
->ptr
);
113 /* advance src pointer after termination symbol */
115 src
->len
-= (token
->len
+ 1);
121 * extracts a name: value pair from the PEM header
123 static bool extract_parameter(chunk_t
*name
, chunk_t
*value
, chunk_t
*line
)
126 if (!extract_token(name
,':', line
))
131 eat_whitespace(line
);
139 * fetches a new line terminated by \n or \r\n
141 static bool fetchline(chunk_t
*src
, chunk_t
*line
)
143 if (src
->len
== 0) /* end of src reached */
146 if (extract_token(line
, '\n', src
))
148 if (line
->len
> 0 && *(line
->ptr
+ line
->len
-1) == '\r')
149 line
->len
--; /* remove optional \r */
151 else /*last line ends without newline */
154 src
->ptr
+= src
->len
;
161 * decrypts a DES-EDE-CBC encrypted data block
163 static status_t
pem_decrypt(chunk_t
*blob
, chunk_t
*iv
, char *passphrase
)
169 chunk_t pass
= {passphrase
, strlen(passphrase
)};
170 chunk_t key
= {alloca(24), 24};
171 u_int8_t padding
, *last_padding_pos
, *first_padding_pos
;
173 /* build key from passphrase and IV */
174 hasher
= hasher_create(HASH_MD5
);
175 hash
.len
= hasher
->get_block_size(hasher
);
176 hash
.ptr
= alloca(hash
.len
);
177 hasher
->get_hash(hasher
, pass
, NULL
);
178 hasher
->get_hash(hasher
, *iv
, hash
.ptr
);
180 memcpy(key
.ptr
, hash
.ptr
, hash
.len
);
182 hasher
->get_hash(hasher
, hash
, NULL
);
183 hasher
->get_hash(hasher
, pass
, NULL
);
184 hasher
->get_hash(hasher
, *iv
, hash
.ptr
);
186 memcpy(key
.ptr
+ hash
.len
, hash
.ptr
, key
.len
- hash
.len
);
188 hasher
->destroy(hasher
);
191 crypter
= crypter_create(ENCR_3DES
, 0);
192 crypter
->set_key(crypter
, key
);
193 crypter
->decrypt(crypter
, *blob
, *iv
, &decrypted
);
194 memcpy(blob
->ptr
, decrypted
.ptr
, blob
->len
);
195 chunk_free(&decrypted
);
197 /* determine amount of padding */
198 last_padding_pos
= blob
->ptr
+ blob
->len
- 1;
199 padding
= *last_padding_pos
;
200 first_padding_pos
= (padding
> blob
->len
) ? blob
->ptr
: last_padding_pos
- padding
;
202 /* check the padding pattern */
203 while (--last_padding_pos
> first_padding_pos
)
205 if (*last_padding_pos
!= padding
)
209 blob
->len
-= padding
;
213 /* Converts a PEM encoded file into its binary form
215 * RFC 1421 Privacy Enhancement for Electronic Mail, February 1993
216 * RFC 934 Message Encapsulation, January 1985
218 status_t
pemtobin(chunk_t
*blob
, char *pass
)
229 bool encrypted
= FALSE
;
231 state_t state
= PEM_PRE
;
235 chunk_t line
= CHUNK_INITIALIZER
;
236 chunk_t iv
= CHUNK_INITIALIZER
;
238 u_char iv_buf
[16]; /* MD5 digest size */
240 /* zero size of converted blob */
243 /* zero size of IV */
247 while (fetchline(&src
, &line
))
249 if (state
== PEM_PRE
)
251 if (find_boundary("BEGIN", &line
))
259 if (find_boundary("END", &line
))
264 if (state
== PEM_MSG
)
266 state
= (memchr(line
.ptr
, ':', line
.len
) == NULL
) ? PEM_BODY
: PEM_HEADER
;
268 if (state
== PEM_HEADER
)
270 chunk_t name
= CHUNK_INITIALIZER
;
271 chunk_t value
= CHUNK_INITIALIZER
;
273 /* an empty line separates HEADER and BODY */
280 /* we are looking for a name: value pair */
281 if (!extract_parameter(&name
, &value
, &line
))
284 if (match("Proc-Type", &name
) && *value
.ptr
== '4')
286 else if (match("DEK-Info", &name
))
288 const char *ugh
= NULL
;
292 if (!extract_token(&dek
, ',', &value
))
295 /* we support DES-EDE3-CBC encrypted files, only */
296 if (!match("DES-EDE3-CBC", &dek
))
297 return NOT_SUPPORTED
;
299 eat_whitespace(&value
);
300 ugh
= ttodata(value
.ptr
, value
.len
, 16, iv
.ptr
, 16, &len
);
307 else /* state is PEM_BODY */
309 const char *ugh
= NULL
;
313 /* remove any trailing whitespace */
314 if (!extract_token(&data
,' ', &line
))
319 ugh
= ttodata(data
.ptr
, data
.len
, 64, dst
.ptr
, blob
->len
- dst
.len
, &len
);
333 /* set length to size of binary blob */
336 if (state
!= PEM_POST
)
340 return pem_decrypt(blob
, &iv
, pass
);