2 * Copyright (C) 2001-2008 Andreas Steffen
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 #include <sys/types.h>
31 #include <asn1/asn1.h>
33 #include <utils/lexparser.h>
34 #include <crypto/hashers/hasher.h>
35 #include <crypto/crypters/crypter.h>
37 #define PKCS5_SALT_LEN 8 /* bytes */
40 * check the presence of a pattern in a character string
42 static bool present(const char* pattern
, chunk_t
* ch
)
44 u_int pattern_len
= strlen(pattern
);
46 if (ch
->len
>= pattern_len
&& strneq(ch
->ptr
, pattern
, pattern_len
))
48 ch
->ptr
+= pattern_len
;
49 ch
->len
-= pattern_len
;
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_empty
;
62 if (!present("-----", line
))
64 if (!present(tag
, line
))
66 if (*line
->ptr
!= ' ')
68 line
->ptr
++; line
->len
--;
74 if (present("-----", line
))
76 DBG2(" -----%s %.*s-----", tag
, (int)name
.len
, name
.ptr
);
79 line
->ptr
++; line
->len
--; name
.len
++;
85 * decrypts a passphrase protected encrypted data block
87 static bool pem_decrypt(chunk_t
*blob
, encryption_algorithm_t alg
, size_t key_size
,
88 chunk_t
*iv
, chunk_t
*passphrase
)
92 chunk_t salt
= { iv
->ptr
, PKCS5_SALT_LEN
};
95 chunk_t key
= {alloca(key_size
), key_size
};
96 u_int8_t padding
, *last_padding_pos
, *first_padding_pos
;
98 if (passphrase
== NULL
|| passphrase
->len
== 0)
100 DBG1(" missing passphrase");
104 /* build key from passphrase and IV */
105 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_MD5
);
108 DBG1(" MD5 hash algorithm not available");
111 hash
.len
= hasher
->get_hash_size(hasher
);
112 hash
.ptr
= alloca(hash
.len
);
113 hasher
->get_hash(hasher
, *passphrase
, NULL
);
114 hasher
->get_hash(hasher
, salt
, hash
.ptr
);
115 memcpy(key
.ptr
, hash
.ptr
, hash
.len
);
117 if (key
.len
> hash
.len
)
119 hasher
->get_hash(hasher
, hash
, NULL
);
120 hasher
->get_hash(hasher
, *passphrase
, NULL
);
121 hasher
->get_hash(hasher
, salt
, hash
.ptr
);
122 memcpy(key
.ptr
+ hash
.len
, hash
.ptr
, key
.len
- hash
.len
);
124 hasher
->destroy(hasher
);
127 crypter
= lib
->crypto
->create_crypter(lib
->crypto
, alg
, key_size
);
130 DBG1(" %N encryption algorithm not available",
131 encryption_algorithm_names
, alg
);
134 crypter
->set_key(crypter
, key
);
136 if (iv
->len
!= crypter
->get_block_size(crypter
) ||
139 crypter
->destroy(crypter
);
140 DBG1(" data size is not multiple of block size");
143 crypter
->decrypt(crypter
, *blob
, *iv
, &decrypted
);
144 crypter
->destroy(crypter
);
145 memcpy(blob
->ptr
, decrypted
.ptr
, blob
->len
);
146 chunk_free(&decrypted
);
148 /* determine amount of padding */
149 last_padding_pos
= blob
->ptr
+ blob
->len
- 1;
150 padding
= *last_padding_pos
;
151 first_padding_pos
= (padding
> blob
->len
) ? blob
->ptr
: last_padding_pos
- padding
;
153 /* check the padding pattern */
154 while (--last_padding_pos
> first_padding_pos
)
156 if (*last_padding_pos
!= padding
)
158 DBG1(" invalid passphrase");
163 blob
->len
-= padding
;
167 /* Converts a PEM encoded file into its binary form
169 * RFC 1421 Privacy Enhancement for Electronic Mail, February 1993
170 * RFC 934 Message Encapsulation, January 1985
172 bool pem_to_bin(chunk_t
*blob
, chunk_t
*passphrase
, bool *pgp
)
183 encryption_algorithm_t alg
= ENCR_UNDEFINED
;
186 bool encrypted
= FALSE
;
188 state_t state
= PEM_PRE
;
192 chunk_t line
= chunk_empty
;
193 chunk_t iv
= chunk_empty
;
195 u_char iv_buf
[16]; /* MD5 digest size */
197 /* zero size of converted blob */
200 /* zero size of IV */
204 while (fetchline(&src
, &line
))
206 if (state
== PEM_PRE
)
208 if (find_boundary("BEGIN", &line
))
216 if (find_boundary("END", &line
))
221 if (state
== PEM_MSG
)
223 state
= (memchr(line
.ptr
, ':', line
.len
) == NULL
) ? PEM_BODY
: PEM_HEADER
;
225 if (state
== PEM_HEADER
)
228 chunk_t name
= chunk_empty
;
229 chunk_t value
= chunk_empty
;
231 /* an empty line separates HEADER and BODY */
238 /* we are looking for a parameter: value pair */
239 DBG2(" %.*s", (int)line
.len
, line
.ptr
);
240 ugh
= extract_parameter_value(&name
, &value
, &line
);
244 if (match("Proc-Type", &name
) && *value
.ptr
== '4')
246 else if (match("DEK-Info", &name
))
250 if (!extract_token(&dek
, ',', &value
))
253 if (match("DES-EDE3-CBC", &dek
))
258 else if (match("AES-128-CBC", &dek
))
263 else if (match("AES-192-CBC", &dek
))
268 else if (match("AES-256-CBC", &dek
))
275 DBG1(" encryption algorithm '%.s' not supported",
279 eat_whitespace(&value
);
280 iv
= chunk_from_hex(value
, iv
.ptr
);
283 else /* state is PEM_BODY */
287 /* remove any trailing whitespace */
288 if (!extract_token(&data
,' ', &line
))
293 /* check for PGP armor checksum */
294 if (*data
.ptr
== '=')
299 DBG2(" armor checksum: %.*s", (int)data
.len
, data
.ptr
);
303 if (blob
->len
- dst
.len
< data
.len
/ 4 * 3)
307 data
= chunk_from_base64(data
, dst
.ptr
);
314 /* set length to size of binary blob */
317 if (state
!= PEM_POST
)
319 DBG1(" file coded in unknown format, discarded");
326 return pem_decrypt(blob
, alg
, key_size
, &iv
, passphrase
);
330 /* load a coded key or certificate file with autodetection
331 * of binary DER or base64 PEM ASN.1 formats and armored PGP format
333 bool pem_asn1_load_file(char *filename
, chunk_t
*passphrase
,
334 chunk_t
*blob
, bool *pgp
)
338 FILE *fd
= fopen(filename
, "r");
343 fseek(fd
, 0, SEEK_END
);
344 blob
->len
= ftell(fd
);
346 blob
->ptr
= malloc(blob
->len
);
347 bytes
= fread(blob
->ptr
, 1, blob
->len
, fd
);
349 DBG2(" loading '%s' (%d bytes)", filename
, bytes
);
356 DBG2(" file coded in DER format");
360 if (passphrase
!= NULL
)
361 DBG4(" passphrase:", passphrase
->ptr
, passphrase
->len
);
364 if (pem_to_bin(blob
, passphrase
, pgp
))
368 DBG2(" file coded in armored PGP format");
373 DBG2(" file coded in PEM format");
376 DBG1(" file coded in unknown format, discarded");
379 /* a conversion error has occured */
384 DBG1(" reading file '%s' failed", filename
);