diff options
Diffstat (limited to 'src/pluto/pem.c')
-rw-r--r-- | src/pluto/pem.c | 420 |
1 files changed, 25 insertions, 395 deletions
diff --git a/src/pluto/pem.c b/src/pluto/pem.c index 98287c215..2378a9c6f 100644 --- a/src/pluto/pem.c +++ b/src/pluto/pem.c @@ -27,10 +27,7 @@ #include <freeswan.h> #include <library.h> -#include <crypto/hashers/hasher.h> - -#define HEADER_DES_LOCL_H /* stupid trick to force prototype decl in <des.h> */ -#include <libdes/des.h> +#include <asn1/pem.h> #include "constants.h" #include "defs.h" @@ -39,238 +36,21 @@ #include "pem.h" /** - * Check the presence of a pattern in a character string - */ -static bool present(const char* pattern, chunk_t* ch) -{ - u_int pattern_len = strlen(pattern); - - if (ch->len >= pattern_len && strneq(ch->ptr, pattern, pattern_len)) - { - ch->ptr += pattern_len; - ch->len -= pattern_len; - return TRUE; - } - return FALSE; -} - -/** - * Compare string with chunk - */ -static bool match(const char *pattern, const chunk_t *ch) -{ - return ch->len == strlen(pattern) && strneq(pattern, ch->ptr, ch->len); -} - -/** - * Find a boundary of the form -----tag name----- - */ -static bool find_boundary(const char* tag, chunk_t *line) -{ - chunk_t name = chunk_empty; - - if (!present("-----", line)) - { - return FALSE; - } - if (!present(tag, line)) - { - return FALSE; - } - if (*line->ptr != ' ') - { - return FALSE; - } - line->ptr++; line->len--; - - /* extract name */ - name.ptr = line->ptr; - while (line->len > 0) - { - if (present("-----", line)) - { - DBG(DBG_PARSING, - DBG_log(" -----%s %.*s-----", - tag, (int)name.len, name.ptr); - ) - return TRUE; - } - line->ptr++; line->len--; name.len++; - } - return FALSE; -} - -/** - * Eat whitespace - */ -static void eat_whitespace(chunk_t *src) -{ - while (src->len > 0 && (*src->ptr == ' ' || *src->ptr == '\t')) - { - src->ptr++; src->len--; - } -} - -/** - * Extracts a token ending with a given termination symbol - */ -static bool extract_token(chunk_t *token, char termination, chunk_t *src) -{ - u_char *eot = memchr(src->ptr, termination, src->len); - - /* initialize empty token */ - *token = chunk_empty; - - if (eot == NULL) /* termination symbol not found */ - { - return FALSE; - } - - /* extract token */ - token->ptr = src->ptr; - token->len = (u_int)(eot - src->ptr); - - /* advance src pointer after termination symbol */ - src->ptr = eot + 1; - src->len -= (token->len + 1); - - return TRUE; -} - -/** - * Extracts a name: value pair from the PEM header - */ -static bool extract_parameter(chunk_t *name, chunk_t *value, chunk_t *line) -{ - DBG(DBG_PARSING, - DBG_log(" %.*s", (int)line->len, line->ptr); - ) - - /* extract name */ - if (!extract_token(name,':', line)) - { - return FALSE; - } - eat_whitespace(line); - - /* extract value */ - *value = *line; - return TRUE; -} - -/** - * Fetches a new line terminated by \n or \r\n - */ -static bool fetchline(chunk_t *src, chunk_t *line) -{ - if (src->len == 0) /* end of src reached */ - { - return FALSE; - } - if (extract_token(line, '\n', src)) - { - if (line->len > 0 && *(line->ptr + line->len -1) == '\r') - { - line->len--; /* remove optional \r */ - } - } - else /*last line ends without newline */ - { - *line = *src; - src->ptr += src->len; - src->len = 0; - } - return TRUE; -} - -/** - * Decrypts a DES-EDE-CBC encrypted data block - */ -static bool pem_decrypt_3des(chunk_t *blob, chunk_t *iv, char *passphrase) -{ - u_char des_iv[DES_CBC_BLOCK_SIZE]; - u_char key[24]; - des_cblock *deskey = (des_cblock *)key; - des_key_schedule ks[3]; - u_char padding, *last_padding_pos, *first_padding_pos; - hasher_t *hasher; - chunk_t digest; - chunk_t passphrase_chunk = { passphrase, strlen(passphrase) }; - - /* Convert passphrase to 3des key */ - hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); - if (hasher == NULL) - { - plog(" passphrase could not be hashed, no MD5 hasher available"); - return FALSE; - } - hasher->allocate_hash(hasher, passphrase_chunk, NULL); - hasher->allocate_hash(hasher, *iv, &digest); - - memcpy(key, digest.ptr, digest.len); - - hasher->get_hash(hasher, digest, NULL); - hasher->get_hash(hasher, passphrase_chunk, NULL); - hasher->get_hash(hasher, *iv, digest.ptr); - hasher->destroy(hasher); - - memcpy(key + digest.len, digest.ptr, 24 - digest.len); - free(digest.ptr); - - (void) des_set_key(&deskey[0], ks[0]); - (void) des_set_key(&deskey[1], ks[1]); - (void) des_set_key(&deskey[2], ks[2]); - - /* decrypt data block */ - memcpy(des_iv, iv->ptr, DES_CBC_BLOCK_SIZE); - des_ede3_cbc_encrypt((des_cblock *)blob->ptr, (des_cblock *)blob->ptr, - blob->len, ks[0], ks[1], ks[2], (des_cblock *)des_iv, FALSE); - - /* determine amount of padding */ - last_padding_pos = blob->ptr + blob->len - 1; - padding = *last_padding_pos; - first_padding_pos = (padding > blob->len)? - blob->ptr : last_padding_pos - padding; - - /* check the padding pattern */ - while (--last_padding_pos > first_padding_pos) - { - if (*last_padding_pos != padding) - { - return FALSE; - } - } - - /* remove padding */ - blob->len -= padding; - return TRUE; -} - -/** - * Optionally prompts for a passphrase before decryption - * currently we support DES-EDE3-CBC, only + * Converts a PEM encoded file into its binary form + * RFC 1421 Privacy Enhancement for Electronic Mail, February 1993 + * RFC 934 Message Encapsulation, January 1985 */ -static err_t pem_decrypt(chunk_t *blob, chunk_t *iv, prompt_pass_t *pass, - const char* label) +err_t pemtobin(chunk_t *blob, prompt_pass_t *pass, const char* label, bool *pgp) { - DBG(DBG_CRYPT, - DBG_log(" decrypting file using 'DES-EDE3-CBC'"); - ) - if (iv->len != DES_CBC_BLOCK_SIZE) - { - return "size of DES-EDE3-CBC IV is not 8 bytes"; - } - if (pass == NULL) - { - return "no passphrase available"; - } + chunk_t password = chunk_empty; /* do we prompt for the passphrase? */ - if (pass->prompt && pass->fd != NULL_FD) + if (pass && pass->prompt && pass->fd != NULL_FD) { int i; chunk_t blob_copy; err_t ugh = "invalid passphrase, too many trials"; + status_t status; whack_log(RC_ENTERSECRET, "need passphrase for '%s'", label); @@ -303,10 +83,19 @@ static err_t pem_decrypt(chunk_t *blob, chunk_t *iv, prompt_pass_t *pass, } blob_copy = chunk_clone(*blob); + password = chunk_create(pass->secret, strlen(pass->secret)); - if (pem_decrypt_3des(blob, iv, pass->secret)) + status = pem_to_bin(blob, password, pgp); + if (status != INVALID_ARG) { - whack_log(RC_SUCCESS, "valid passphrase"); + if (status == SUCCESS) + { + whack_log(RC_SUCCESS, "valid passphrase"); + } + else + { + whack_log(RC_LOG_SERIOUS, "%N, aborted", status_names, status); + } free(blob_copy.ptr); return NULL; } @@ -320,176 +109,17 @@ static err_t pem_decrypt(chunk_t *blob, chunk_t *iv, prompt_pass_t *pass, } else { - if (pem_decrypt_3des(blob, iv, pass->secret)) - { - return NULL; - } - else + if (pass) { - return "invalid passphrase"; + password = chunk_create(pass->secret, strlen(pass->secret)); } - } -} - -/* Converts a PEM encoded file into its binary form - * - * RFC 1421 Privacy Enhancement for Electronic Mail, February 1993 - * RFC 934 Message Encapsulation, January 1985 - */ -err_t pemtobin(chunk_t *blob, prompt_pass_t *pass, const char* label, bool *pgp) -{ - typedef enum { - PEM_PRE = 0, - PEM_MSG = 1, - PEM_HEADER = 2, - PEM_BODY = 3, - PEM_POST = 4, - PEM_ABORT = 5 - } state_t; - - bool encrypted = FALSE; - - state_t state = PEM_PRE; - - chunk_t src = *blob; - chunk_t dst = *blob; - chunk_t line = chunk_empty; - chunk_t iv = chunk_empty; - - u_char iv_buf[MAX_DIGEST_LEN]; - - /* zero size of converted blob */ - dst.len = 0; - - /* zero size of IV */ - iv.ptr = iv_buf; - iv.len = 0; - - while (fetchline(&src, &line)) - { - if (state == PEM_PRE) + if (pem_to_bin(blob, password, pgp) == SUCCESS) { - if (find_boundary("BEGIN", &line)) - { - *pgp = FALSE; - state = PEM_MSG; - } - continue; + return NULL; } else { - if (find_boundary("END", &line)) - { - state = PEM_POST; - break; - } - if (state == PEM_MSG) - { - state = (memchr(line.ptr, ':', line.len) == NULL)? - PEM_BODY : PEM_HEADER; - } - if (state == PEM_HEADER) - { - chunk_t name = chunk_empty; - chunk_t value = chunk_empty; - - /* an empty line separates HEADER and BODY */ - if (line.len == 0) - { - state = PEM_BODY; - continue; - } - - /* we are looking for a name: value pair */ - if (!extract_parameter(&name, &value, &line)) - { - continue; - } - if (match("Proc-Type", &name) && *value.ptr == '4') - { - encrypted = TRUE; - } - else if (match("DEK-Info", &name)) - { - const char *ugh = NULL; - size_t len = 0; - chunk_t dek; - - if (!extract_token(&dek, ',', &value)) - { - dek = value; - } - - /* we support DES-EDE3-CBC encrypted files, only */ - if (!match("DES-EDE3-CBC", &dek)) - { - return "we support DES-EDE3-CBC encrypted files, only"; - } - eat_whitespace(&value); - ugh = ttodata(value.ptr, value.len, 16, - iv.ptr, MAX_DIGEST_LEN, &len); - if (ugh) - { - return "error in IV"; - } - iv.len = len; - } - } - else /* state is PEM_BODY */ - { - const char *ugh = NULL; - size_t len = 0; - chunk_t data; - - /* remove any trailing whitespace */ - if (!extract_token(&data ,' ', &line)) - { - data = line; - } - - /* check for PGP armor checksum */ - if (*data.ptr == '=') - { - *pgp = TRUE; - data.ptr++; - data.len--; - DBG(DBG_PARSING, - DBG_log(" Armor checksum: %.*s", (int)data.len, data.ptr); - ) - continue; - } - - ugh = ttodata(data.ptr, data.len, 64, - dst.ptr, blob->len - dst.len, &len); - if (ugh) - { - DBG(DBG_PARSING, - DBG_log(" %s", ugh); - ) - state = PEM_ABORT; - break; - } - else - { - dst.ptr += len; - dst.len += len; - } - } + return "pem to bin conversion failed"; } - } - /* set length to size of binary blob */ - blob->len = dst.len; - - if (state != PEM_POST) - { - return "file coded in unknown format, discarded"; - } - if (encrypted) - { - return pem_decrypt(blob, &iv, pass, label); - } - else - { - return NULL; - } + } } |