Return to pem_builder.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / plugins / pem |
1.1 misho 1: /* 2: * Copyright (C) 2013 Tobias Brunner 3: * Copyright (C) 2009 Martin Willi 4: * Copyright (C) 2001-2008 Andreas Steffen 5: * HSR Hochschule fuer Technik Rapperswil 6: * 7: * This program is free software; you can redistribute it and/or modify it 8: * under the terms of the GNU General Public License as published by the 9: * Free Software Foundation; either version 2 of the License, or (at your 10: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. 11: * 12: * This program is distributed in the hope that it will be useful, but 13: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15: * for more details. 16: */ 17: 18: #include "pem_builder.h" 19: 20: #include <stdio.h> 21: #include <stdlib.h> 22: #include <unistd.h> 23: #include <errno.h> 24: #include <string.h> 25: #include <stddef.h> 26: #include <fcntl.h> 27: #include <sys/types.h> 28: #include <sys/stat.h> 29: 30: #include <utils/debug.h> 31: #include <library.h> 32: #include <utils/lexparser.h> 33: #include <asn1/asn1.h> 34: #include <crypto/hashers/hasher.h> 35: #include <crypto/crypters/crypter.h> 36: #include <credentials/certificates/x509.h> 37: 38: #define PKCS5_SALT_LEN 8 /* bytes */ 39: 40: /** 41: * check the presence of a pattern in a character string, skip if found 42: */ 43: static bool present(char* pattern, chunk_t* ch) 44: { 45: u_int len = strlen(pattern); 46: 47: if (ch->len >= len && strneq(ch->ptr, pattern, len)) 48: { 49: *ch = chunk_skip(*ch, len); 50: return TRUE; 51: } 52: return FALSE; 53: } 54: 55: /** 56: * find a boundary of the form -----tag name----- 57: */ 58: static bool find_boundary(char* tag, chunk_t *line) 59: { 60: chunk_t name = chunk_empty; 61: 62: if (!present("-----", line) || 63: !present(tag, line) || 64: !line->len || *line->ptr != ' ') 65: { 66: return FALSE; 67: } 68: *line = chunk_skip(*line, 1); 69: 70: /* extract name */ 71: name.ptr = line->ptr; 72: while (line->len > 0) 73: { 74: if (present("-----", line)) 75: { 76: DBG2(DBG_ASN, " -----%s %.*s-----", tag, (int)name.len, name.ptr); 77: return TRUE; 78: } 79: line->ptr++; line->len--; name.len++; 80: } 81: return FALSE; 82: } 83: 84: /* 85: * decrypts a passphrase protected encrypted data block 86: */ 87: static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, 88: size_t key_size, chunk_t iv, chunk_t passphrase) 89: { 90: hasher_t *hasher; 91: crypter_t *crypter; 92: chunk_t salt = { iv.ptr, PKCS5_SALT_LEN }; 93: chunk_t hash; 94: chunk_t decrypted; 95: chunk_t key = {alloca(key_size), key_size}; 96: uint8_t padding, *last_padding_pos, *first_padding_pos; 97: 98: /* build key from passphrase and IV */ 99: hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); 100: if (hasher == NULL) 101: { 102: DBG1(DBG_ASN, " MD5 hash algorithm not available"); 103: return NOT_SUPPORTED; 104: } 105: hash.len = hasher->get_hash_size(hasher); 106: hash.ptr = alloca(hash.len); 107: if (!hasher->get_hash(hasher, passphrase, NULL) || 108: !hasher->get_hash(hasher, salt, hash.ptr)) 109: { 110: return FAILED; 111: } 112: memcpy(key.ptr, hash.ptr, hash.len); 113: 114: if (key.len > hash.len) 115: { 116: if (!hasher->get_hash(hasher, hash, NULL) || 117: !hasher->get_hash(hasher, passphrase, NULL) || 118: !hasher->get_hash(hasher, salt, hash.ptr)) 119: { 120: return FAILED; 121: } 122: memcpy(key.ptr + hash.len, hash.ptr, key.len - hash.len); 123: } 124: hasher->destroy(hasher); 125: 126: /* decrypt blob */ 127: crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size); 128: if (crypter == NULL) 129: { 130: DBG1(DBG_ASN, " %N encryption algorithm not available", 131: encryption_algorithm_names, alg); 132: return NOT_SUPPORTED; 133: } 134: 135: if (iv.len != crypter->get_iv_size(crypter) || 136: blob->len % crypter->get_block_size(crypter)) 137: { 138: crypter->destroy(crypter); 139: DBG1(DBG_ASN, " data size is not multiple of block size"); 140: return PARSE_ERROR; 141: } 142: if (!crypter->set_key(crypter, key) || 143: !crypter->decrypt(crypter, *blob, iv, &decrypted)) 144: { 145: crypter->destroy(crypter); 146: return FAILED; 147: } 148: crypter->destroy(crypter); 149: memcpy(blob->ptr, decrypted.ptr, blob->len); 150: chunk_free(&decrypted); 151: 152: /* determine amount of padding */ 153: last_padding_pos = blob->ptr + blob->len - 1; 154: padding = *last_padding_pos; 155: if (padding > blob->len) 156: { 157: first_padding_pos = blob->ptr; 158: } 159: else 160: { 161: first_padding_pos = last_padding_pos - padding; 162: } 163: /* check the padding pattern */ 164: while (--last_padding_pos > first_padding_pos) 165: { 166: if (*last_padding_pos != padding) 167: { 168: DBG1(DBG_ASN, " invalid passphrase"); 169: return INVALID_ARG; 170: } 171: } 172: /* remove padding */ 173: blob->len -= padding; 174: return SUCCESS; 175: } 176: 177: /** 178: * Converts a PEM encoded file into its binary form (RFC 1421, RFC 934) 179: */ 180: static status_t pem_to_bin(chunk_t *blob, bool *pgp) 181: { 182: typedef enum { 183: PEM_PRE = 0, 184: PEM_MSG = 1, 185: PEM_HEADER = 2, 186: PEM_BODY = 3, 187: PEM_POST = 4, 188: PEM_ABORT = 5 189: } state_t; 190: 191: encryption_algorithm_t alg = ENCR_UNDEFINED; 192: size_t key_size = 0; 193: bool encrypted = FALSE; 194: state_t state = PEM_PRE; 195: chunk_t src = *blob; 196: chunk_t dst = *blob; 197: chunk_t line = chunk_empty; 198: chunk_t iv = chunk_empty; 199: u_char iv_buf[HASH_SIZE_MD5]; 200: status_t status = NOT_FOUND; 201: enumerator_t *enumerator; 202: shared_key_t *shared; 203: 204: dst.len = 0; 205: iv.ptr = iv_buf; 206: iv.len = 0; 207: 208: while (fetchline(&src, &line)) 209: { 210: if (state == PEM_PRE) 211: { 212: if (find_boundary("BEGIN", &line)) 213: { 214: state = PEM_MSG; 215: } 216: continue; 217: } 218: else 219: { 220: if (find_boundary("END", &line)) 221: { 222: state = PEM_POST; 223: break; 224: } 225: if (state == PEM_MSG) 226: { 227: state = PEM_HEADER; 228: if (memchr(line.ptr, ':', line.len) == NULL) 229: { 230: state = PEM_BODY; 231: } 232: } 233: if (state == PEM_HEADER) 234: { 235: err_t ugh = NULL; 236: chunk_t name = chunk_empty; 237: chunk_t value = chunk_empty; 238: 239: /* an empty line separates HEADER and BODY */ 240: if (line.len == 0) 241: { 242: state = PEM_BODY; 243: continue; 244: } 245: 246: /* we are looking for a parameter: value pair */ 247: DBG2(DBG_ASN, " %.*s", (int)line.len, line.ptr); 248: ugh = extract_parameter_value(&name, &value, &line); 249: if (ugh != NULL) 250: { 251: continue; 252: } 253: if (match("Proc-Type", &name) && value.len && *value.ptr == '4') 254: { 255: encrypted = TRUE; 256: } 257: else if (match("DEK-Info", &name)) 258: { 259: chunk_t dek; 260: 261: if (!extract_token(&dek, ',', &value)) 262: { 263: dek = value; 264: } 265: if (match("DES-EDE3-CBC", &dek)) 266: { 267: alg = ENCR_3DES; 268: key_size = 24; 269: } 270: else if (match("AES-128-CBC", &dek)) 271: { 272: alg = ENCR_AES_CBC; 273: key_size = 16; 274: } 275: else if (match("AES-192-CBC", &dek)) 276: { 277: alg = ENCR_AES_CBC; 278: key_size = 24; 279: } 280: else if (match("AES-256-CBC", &dek)) 281: { 282: alg = ENCR_AES_CBC; 283: key_size = 32; 284: } 285: else 286: { 287: DBG1(DBG_ASN, " encryption algorithm '%.*s'" 288: " not supported", (int)dek.len, dek.ptr); 289: return NOT_SUPPORTED; 290: } 291: if (!eat_whitespace(&value) || value.len > 2*sizeof(iv_buf)) 292: { 293: return PARSE_ERROR; 294: } 295: iv = chunk_from_hex(value, iv_buf); 296: } 297: } 298: else /* state is PEM_BODY */ 299: { 300: chunk_t data; 301: 302: /* remove any trailing whitespace */ 303: if (!extract_token(&data ,' ', &line)) 304: { 305: data = line; 306: } 307: 308: /* check for PGP armor checksum */ 309: if (data.len && *data.ptr == '=') 310: { 311: *pgp = TRUE; 312: data.ptr++; 313: data.len--; 314: DBG2(DBG_ASN, " armor checksum: %.*s", (int)data.len, 315: data.ptr); 316: continue; 317: } 318: 319: if (blob->len - dst.len < data.len / 4 * 3) 320: { 321: state = PEM_ABORT; 322: } 323: data = chunk_from_base64(data, dst.ptr); 324: 325: dst.ptr += data.len; 326: dst.len += data.len; 327: } 328: } 329: } 330: /* set length to size of binary blob */ 331: blob->len = dst.len; 332: 333: if (state != PEM_POST) 334: { 335: DBG1(DBG_LIB, " file coded in unknown format, discarded"); 336: return PARSE_ERROR; 337: } 338: if (!encrypted) 339: { 340: return SUCCESS; 341: } 342: 343: enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, 344: SHARED_PRIVATE_KEY_PASS, NULL, NULL); 345: while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) 346: { 347: chunk_t passphrase, chunk; 348: 349: passphrase = shared->get_key(shared); 350: chunk = chunk_clone(*blob); 351: status = pem_decrypt(&chunk, alg, key_size, iv, passphrase); 352: if (status == SUCCESS) 353: { 354: memcpy(blob->ptr, chunk.ptr, chunk.len); 355: blob->len = chunk.len; 356: } 357: free(chunk.ptr); 358: if (status != INVALID_ARG) 359: { /* try again only if passphrase invalid */ 360: break; 361: } 362: } 363: enumerator->destroy(enumerator); 364: return status; 365: } 366: 367: /** 368: * Check if a blob looks like an ASN1 SEQUENCE or SET with BER indefinite length 369: */ 370: static bool is_ber_indefinite_length(chunk_t blob) 371: { 372: if (blob.len >= 4) 373: { 374: switch (blob.ptr[0]) 375: { 376: case ASN1_SEQUENCE: 377: case ASN1_SET: 378: /* BER indefinite length uses 0x80, and is terminated with 379: * end-of-content using 0x00,0x00 */ 380: return blob.ptr[1] == 0x80 && 381: blob.ptr[blob.len - 2] == 0 && 382: blob.ptr[blob.len - 1] == 0; 383: default: 384: break; 385: } 386: } 387: return FALSE; 388: } 389: 390: /** 391: * load the credential from a blob 392: */ 393: static void *load_from_blob(chunk_t blob, credential_type_t type, int subtype, 394: identification_t *subject, x509_flag_t flags) 395: { 396: void *cred = NULL; 397: bool pgp = FALSE; 398: 399: blob = chunk_clone(blob); 400: if (!is_ber_indefinite_length(blob) && !is_asn1(blob)) 401: { 402: if (pem_to_bin(&blob, &pgp) != SUCCESS) 403: { 404: chunk_clear(&blob); 405: return NULL; 406: } 407: if (pgp && type == CRED_PRIVATE_KEY) 408: { 409: /* PGP encoded keys are parsed with a KEY_ANY key type, as it 410: * can contain any type of key. However, ipsec.secrets uses 411: * RSA for PGP keys, which is actually wrong. */ 412: subtype = KEY_ANY; 413: } 414: } 415: /* if CERT_ANY is given, ASN1 encoded blob is handled as X509 */ 416: if (type == CRED_CERTIFICATE && subtype == CERT_ANY) 417: { 418: subtype = pgp ? CERT_GPG : CERT_X509; 419: } 420: if (type == CRED_CERTIFICATE && subtype == CERT_TRUSTED_PUBKEY && subject) 421: { 422: cred = lib->creds->create(lib->creds, type, subtype, 423: BUILD_BLOB_ASN1_DER, blob, BUILD_SUBJECT, subject, 424: BUILD_END); 425: } 426: else 427: { 428: cred = lib->creds->create(lib->creds, type, subtype, 429: pgp ? BUILD_BLOB_PGP : BUILD_BLOB_ASN1_DER, blob, 430: flags ? BUILD_X509_FLAG : BUILD_END, 431: flags, BUILD_END); 432: } 433: chunk_clear(&blob); 434: return cred; 435: } 436: 437: /** 438: * load the credential from a file 439: */ 440: static void *load_from_file(char *file, credential_type_t type, int subtype, 441: identification_t *subject, x509_flag_t flags) 442: { 443: void *cred; 444: chunk_t *chunk; 445: 446: chunk = chunk_map(file, FALSE); 447: if (!chunk) 448: { 449: DBG1(DBG_LIB, " opening '%s' failed: %s", file, strerror(errno)); 450: return NULL; 451: } 452: cred = load_from_blob(*chunk, type, subtype, subject, flags); 453: chunk_unmap(chunk); 454: return cred; 455: } 456: 457: /** 458: * Load all kind of PEM encoded credentials. 459: */ 460: static void *pem_load(credential_type_t type, int subtype, va_list args) 461: { 462: char *file = NULL; 463: chunk_t pem = chunk_empty; 464: identification_t *subject = NULL; 465: int flags = 0; 466: 467: while (TRUE) 468: { 469: switch (va_arg(args, builder_part_t)) 470: { 471: case BUILD_FROM_FILE: 472: file = va_arg(args, char*); 473: continue; 474: case BUILD_BLOB: 475: case BUILD_BLOB_PEM: 476: pem = va_arg(args, chunk_t); 477: continue; 478: case BUILD_SUBJECT: 479: subject = va_arg(args, identification_t*); 480: continue; 481: case BUILD_X509_FLAG: 482: flags = va_arg(args, int); 483: continue; 484: case BUILD_END: 485: break; 486: default: 487: return NULL; 488: } 489: break; 490: } 491: 492: if (pem.len) 493: { 494: return load_from_blob(pem, type, subtype, subject, flags); 495: } 496: if (file) 497: { 498: return load_from_file(file, type, subtype, subject, flags); 499: } 500: return NULL; 501: } 502: 503: /** 504: * Private key PEM loader. 505: */ 506: private_key_t *pem_private_key_load(key_type_t type, va_list args) 507: { 508: return pem_load(CRED_PRIVATE_KEY, type, args); 509: } 510: 511: /** 512: * Public key PEM loader. 513: */ 514: public_key_t *pem_public_key_load(key_type_t type, va_list args) 515: { 516: return pem_load(CRED_PUBLIC_KEY, type, args); 517: } 518: 519: /** 520: * Certificate PEM loader. 521: */ 522: certificate_t *pem_certificate_load(certificate_type_t type, va_list args) 523: { 524: return pem_load(CRED_CERTIFICATE, type, args); 525: } 526: 527: /** 528: * Container PEM loader. 529: */ 530: container_t *pem_container_load(container_type_t type, va_list args) 531: { 532: return pem_load(CRED_CONTAINER, type, args); 533: }