Annotation of embedaddon/axTLS/ssl/p12.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 2007, Cameron Rich
! 3: *
! 4: * All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions are met:
! 8: *
! 9: * * Redistributions of source code must retain the above copyright notice,
! 10: * this list of conditions and the following disclaimer.
! 11: * * Redistributions in binary form must reproduce the above copyright notice,
! 12: * this list of conditions and the following disclaimer in the documentation
! 13: * and/or other materials provided with the distribution.
! 14: * * Neither the name of the axTLS project nor the names of its contributors
! 15: * may be used to endorse or promote products derived from this software
! 16: * without specific prior written permission.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
! 19: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
! 20: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
! 21: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
! 22: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
! 23: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 24: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
! 25: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
! 26: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
! 27: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
! 28: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 29: */
! 30:
! 31: /**
! 32: * Process PKCS#8/PKCS#12 keys.
! 33: *
! 34: * The decoding of a PKCS#12 key is fairly specific - this code was tested on a
! 35: * key generated with:
! 36: *
! 37: * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
! 38: * -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128
! 39: * -name "p12_withoutCA" -out axTLS.withoutCA.p12 -password pass:abcd
! 40: *
! 41: * or with a certificate chain:
! 42: *
! 43: * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
! 44: * -certfile axTLS.ca_x509.pem -keypbe PBE-SHA1-RC4-128 -certpbe
! 45: * PBE-SHA1-RC4-128 -name "p12_withCA" -out axTLS.withCA.p12 -password pass:abcd
! 46: *
! 47: * Note that the PBE has to be specified with PBE-SHA1-RC4-128. The
! 48: * private/public keys/certs have to use RSA encryption. Both the integrity
! 49: * and privacy passwords are the same.
! 50: *
! 51: * The PKCS#8 files were generated with something like:
! 52: *
! 53: * PEM format:
! 54: * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -v1
! 55: * PBE-SHA1-RC4-128 -out axTLS.encrypted_pem.p8
! 56: *
! 57: * DER format:
! 58: * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -outform DER
! 59: * -v1 PBE-SHA1-RC4-128 -out axTLS.encrypted.p8
! 60: */
! 61:
! 62: #include <stdlib.h>
! 63: #include <string.h>
! 64: #include <stdio.h>
! 65: #include "os_port.h"
! 66: #include "ssl.h"
! 67:
! 68: /* all commented out if not used */
! 69: #ifdef CONFIG_SSL_USE_PKCS12
! 70:
! 71: #define BLOCK_SIZE 64
! 72: #define PKCS12_KEY_ID 1
! 73: #define PKCS12_IV_ID 2
! 74: #define PKCS12_MAC_ID 3
! 75:
! 76: static char *make_uni_pass(const char *password, int *uni_pass_len);
! 77: static int p8_decrypt(const char *uni_pass, int uni_pass_len,
! 78: const uint8_t *salt, int iter,
! 79: uint8_t *priv_key, int priv_key_len, int id);
! 80: static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key);
! 81: static int get_pbe_params(uint8_t *buf, int *offset,
! 82: const uint8_t **salt, int *iterations);
! 83:
! 84: /*
! 85: * Take a raw pkcs8 block and then decrypt it and turn it into a normal key.
! 86: */
! 87: int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
! 88: {
! 89: uint8_t *buf = ssl_obj->buf;
! 90: int len, offset = 0;
! 91: int iterations;
! 92: int ret = SSL_NOT_OK;
! 93: uint8_t *version = NULL;
! 94: const uint8_t *salt;
! 95: uint8_t *priv_key;
! 96: int uni_pass_len;
! 97: char *uni_pass = make_uni_pass(password, &uni_pass_len);
! 98:
! 99: if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)
! 100: {
! 101: #ifdef CONFIG_SSL_FULL_MODE
! 102: printf("Error: Invalid p8 ASN.1 file\n");
! 103: #endif
! 104: goto error;
! 105: }
! 106:
! 107: /* unencrypted key? */
! 108: if (asn1_get_int(buf, &offset, &version) > 0 && *version == 0)
! 109: {
! 110: ret = p8_add_key(ssl_ctx, buf);
! 111: goto error;
! 112: }
! 113:
! 114: if (get_pbe_params(buf, &offset, &salt, &iterations) < 0)
! 115: goto error;
! 116:
! 117: if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
! 118: goto error;
! 119:
! 120: priv_key = &buf[offset];
! 121:
! 122: p8_decrypt(uni_pass, uni_pass_len, salt,
! 123: iterations, priv_key, len, PKCS12_KEY_ID);
! 124: ret = p8_add_key(ssl_ctx, priv_key);
! 125:
! 126: error:
! 127: free(version);
! 128: free(uni_pass);
! 129: return ret;
! 130: }
! 131:
! 132: /*
! 133: * Take the unencrypted pkcs8 and turn it into a private key
! 134: */
! 135: static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key)
! 136: {
! 137: uint8_t *buf = priv_key;
! 138: int len, offset = 0;
! 139: int ret = SSL_NOT_OK;
! 140:
! 141: /* Skip the preamble and go straight to the private key.
! 142: We only support rsaEncryption (1.2.840.113549.1.1.1) */
! 143: if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 144: asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||
! 145: asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 146: (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
! 147: goto error;
! 148:
! 149: ret = asn1_get_private_key(&buf[offset], len, &ssl_ctx->rsa_ctx);
! 150:
! 151: error:
! 152: return ret;
! 153: }
! 154:
! 155: /*
! 156: * Create the unicode password
! 157: */
! 158: static char *make_uni_pass(const char *password, int *uni_pass_len)
! 159: {
! 160: int pass_len = 0, i;
! 161: char *uni_pass;
! 162:
! 163: if (password == NULL)
! 164: {
! 165: password = "";
! 166: }
! 167:
! 168: uni_pass = (char *)malloc((strlen(password)+1)*2);
! 169:
! 170: /* modify the password into a unicode version */
! 171: for (i = 0; i < (int)strlen(password); i++)
! 172: {
! 173: uni_pass[pass_len++] = 0;
! 174: uni_pass[pass_len++] = password[i];
! 175: }
! 176:
! 177: uni_pass[pass_len++] = 0; /* null terminate */
! 178: uni_pass[pass_len++] = 0;
! 179: *uni_pass_len = pass_len;
! 180: return uni_pass;
! 181: }
! 182:
! 183: /*
! 184: * Decrypt a pkcs8 block.
! 185: */
! 186: static int p8_decrypt(const char *uni_pass, int uni_pass_len,
! 187: const uint8_t *salt, int iter,
! 188: uint8_t *priv_key, int priv_key_len, int id)
! 189: {
! 190: uint8_t p[BLOCK_SIZE*2];
! 191: uint8_t d[BLOCK_SIZE];
! 192: uint8_t Ai[SHA1_SIZE];
! 193: SHA1_CTX sha_ctx;
! 194: RC4_CTX rc4_ctx;
! 195: int i;
! 196:
! 197: for (i = 0; i < BLOCK_SIZE; i++)
! 198: {
! 199: p[i] = salt[i % SALT_SIZE];
! 200: p[BLOCK_SIZE+i] = uni_pass[i % uni_pass_len];
! 201: d[i] = id;
! 202: }
! 203:
! 204: /* get the key - no IV since we are using RC4 */
! 205: SHA1_Init(&sha_ctx);
! 206: SHA1_Update(&sha_ctx, d, sizeof(d));
! 207: SHA1_Update(&sha_ctx, p, sizeof(p));
! 208: SHA1_Final(Ai, &sha_ctx);
! 209:
! 210: for (i = 1; i < iter; i++)
! 211: {
! 212: SHA1_Init(&sha_ctx);
! 213: SHA1_Update(&sha_ctx, Ai, SHA1_SIZE);
! 214: SHA1_Final(Ai, &sha_ctx);
! 215: }
! 216:
! 217: /* do the decryption */
! 218: if (id == PKCS12_KEY_ID)
! 219: {
! 220: RC4_setup(&rc4_ctx, Ai, 16);
! 221: RC4_crypt(&rc4_ctx, priv_key, priv_key, priv_key_len);
! 222: }
! 223: else /* MAC */
! 224: memcpy(priv_key, Ai, SHA1_SIZE);
! 225:
! 226: return 0;
! 227: }
! 228:
! 229: /*
! 230: * Take a raw pkcs12 block and the decrypt it and turn it into a certificate(s)
! 231: * and keys.
! 232: */
! 233: int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
! 234: {
! 235: uint8_t *buf = ssl_obj->buf;
! 236: int len, iterations, auth_safes_start,
! 237: auth_safes_end, auth_safes_len, key_offset, offset = 0;
! 238: int all_certs = 0;
! 239: uint8_t *version = NULL, *auth_safes = NULL, *cert, *orig_mac;
! 240: uint8_t key[SHA1_SIZE];
! 241: uint8_t mac[SHA1_SIZE];
! 242: const uint8_t *salt;
! 243: int uni_pass_len, ret = SSL_OK;
! 244: char *uni_pass = make_uni_pass(password, &uni_pass_len);
! 245: static const uint8_t pkcs_data[] = /* pkc7 data */
! 246: { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 };
! 247: static const uint8_t pkcs_encrypted[] = /* pkc7 encrypted */
! 248: { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06 };
! 249: static const uint8_t pkcs8_key_bag[] = /* 1.2.840.113549.1.12.10.1.2 */
! 250: { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02 };
! 251:
! 252: if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)
! 253: {
! 254: #ifdef CONFIG_SSL_FULL_MODE
! 255: printf("Error: Invalid p12 ASN.1 file\n");
! 256: #endif
! 257: goto error;
! 258: }
! 259:
! 260: if (asn1_get_int(buf, &offset, &version) < 0 || *version != 3)
! 261: {
! 262: ret = SSL_ERROR_INVALID_VERSION;
! 263: goto error;
! 264: }
! 265:
! 266: /* remove all the boring pcks7 bits */
! 267: if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 268: (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
! 269: len != sizeof(pkcs_data) ||
! 270: memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
! 271: goto error;
! 272:
! 273: offset += len;
! 274:
! 275: if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
! 276: asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0)
! 277: goto error;
! 278:
! 279: /* work out the MAC start/end points (done on AuthSafes) */
! 280: auth_safes_start = offset;
! 281: auth_safes_end = offset;
! 282: if (asn1_skip_obj(buf, &auth_safes_end, ASN1_SEQUENCE) < 0)
! 283: goto error;
! 284:
! 285: auth_safes_len = auth_safes_end - auth_safes_start;
! 286: auth_safes = malloc(auth_safes_len);
! 287:
! 288: memcpy(auth_safes, &buf[auth_safes_start], auth_safes_len);
! 289:
! 290: if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 291: asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 292: (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
! 293: (len != sizeof(pkcs_encrypted) ||
! 294: memcmp(&buf[offset], pkcs_encrypted, sizeof(pkcs_encrypted))))
! 295: goto error;
! 296:
! 297: offset += len;
! 298:
! 299: if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
! 300: asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 301: asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||
! 302: asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 303: (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
! 304: len != sizeof(pkcs_data) ||
! 305: memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
! 306: goto error;
! 307:
! 308: offset += len;
! 309:
! 310: /* work out the salt for the certificate */
! 311: if (get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||
! 312: (len = asn1_next_obj(buf, &offset, ASN1_IMPLICIT_TAG)) < 0)
! 313: goto error;
! 314:
! 315: /* decrypt the certificate */
! 316: cert = &buf[offset];
! 317: if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert,
! 318: len, PKCS12_KEY_ID)) < 0)
! 319: goto error;
! 320:
! 321: offset += len;
! 322:
! 323: /* load the certificate */
! 324: key_offset = 0;
! 325: all_certs = asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE);
! 326:
! 327: /* keep going until all certs are loaded */
! 328: while (key_offset < all_certs)
! 329: {
! 330: int cert_offset = key_offset;
! 331:
! 332: if (asn1_skip_obj(cert, &cert_offset, ASN1_SEQUENCE) < 0 ||
! 333: asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||
! 334: asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||
! 335: asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||
! 336: asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||
! 337: asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||
! 338: asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||
! 339: (len = asn1_next_obj(cert, &key_offset, ASN1_OCTET_STRING)) < 0)
! 340: goto error;
! 341:
! 342: if ((ret = add_cert(ssl_ctx, &cert[key_offset], len)) < 0)
! 343: goto error;
! 344:
! 345: key_offset = cert_offset;
! 346: }
! 347:
! 348: if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 349: (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
! 350: len != sizeof(pkcs_data) ||
! 351: memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
! 352: goto error;
! 353:
! 354: offset += len;
! 355:
! 356: if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
! 357: asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0 ||
! 358: asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 359: asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 360: (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
! 361: (len != sizeof(pkcs8_key_bag)) ||
! 362: memcmp(&buf[offset], pkcs8_key_bag, sizeof(pkcs8_key_bag)))
! 363: goto error;
! 364:
! 365: offset += len;
! 366:
! 367: /* work out the salt for the private key */
! 368: if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
! 369: asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 370: get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||
! 371: (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
! 372: goto error;
! 373:
! 374: /* decrypt the private key */
! 375: cert = &buf[offset];
! 376: if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert,
! 377: len, PKCS12_KEY_ID)) < 0)
! 378: goto error;
! 379:
! 380: offset += len;
! 381:
! 382: /* load the private key */
! 383: if ((ret = p8_add_key(ssl_ctx, cert)) < 0)
! 384: goto error;
! 385:
! 386: /* miss out on friendly name, local key id etc */
! 387: if (asn1_skip_obj(buf, &offset, ASN1_SET) < 0)
! 388: goto error;
! 389:
! 390: /* work out the MAC */
! 391: if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 392: asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 393: asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
! 394: (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 ||
! 395: len != SHA1_SIZE)
! 396: goto error;
! 397:
! 398: orig_mac = &buf[offset];
! 399: offset += len;
! 400:
! 401: /* get the salt */
! 402: if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || len != 8)
! 403: goto error;
! 404:
! 405: salt = &buf[offset];
! 406:
! 407: /* work out what the mac should be */
! 408: if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations,
! 409: key, SHA1_SIZE, PKCS12_MAC_ID)) < 0)
! 410: goto error;
! 411:
! 412: hmac_sha1(auth_safes, auth_safes_len, key, SHA1_SIZE, mac);
! 413:
! 414: if (memcmp(mac, orig_mac, SHA1_SIZE))
! 415: {
! 416: ret = SSL_ERROR_INVALID_HMAC;
! 417: goto error;
! 418: }
! 419:
! 420: error:
! 421: free(version);
! 422: free(uni_pass);
! 423: free(auth_safes);
! 424: return ret;
! 425: }
! 426:
! 427: /*
! 428: * Retrieve the salt/iteration details from a PBE block.
! 429: */
! 430: static int get_pbe_params(uint8_t *buf, int *offset,
! 431: const uint8_t **salt, int *iterations)
! 432: {
! 433: static const uint8_t pbeSH1RC4[] = /* pbeWithSHAAnd128BitRC4 */
! 434: { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01 };
! 435:
! 436: int i, len;
! 437: uint8_t *iter = NULL;
! 438: int error_code = SSL_ERROR_NOT_SUPPORTED;
! 439:
! 440: /* Get the PBE type */
! 441: if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||
! 442: (len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
! 443: goto error;
! 444:
! 445: /* we expect pbeWithSHAAnd128BitRC4 (1.2.840.113549.1.12.1.1)
! 446: which is the only algorithm we support */
! 447: if (len != sizeof(pbeSH1RC4) ||
! 448: memcmp(&buf[*offset], pbeSH1RC4, sizeof(pbeSH1RC4)))
! 449: {
! 450: #ifdef CONFIG_SSL_FULL_MODE
! 451: printf("Error: pkcs8/pkcs12 must use \"PBE-SHA1-RC4-128\"\n");
! 452: #endif
! 453: goto error;
! 454: }
! 455:
! 456: *offset += len;
! 457:
! 458: if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||
! 459: (len = asn1_next_obj(buf, offset, ASN1_OCTET_STRING)) < 0 ||
! 460: len != 8)
! 461: goto error;
! 462:
! 463: *salt = &buf[*offset];
! 464: *offset += len;
! 465:
! 466: if ((len = asn1_get_int(buf, offset, &iter)) < 0)
! 467: goto error;
! 468:
! 469: *iterations = 0;
! 470: for (i = 0; i < len; i++)
! 471: {
! 472: (*iterations) <<= 8;
! 473: (*iterations) += iter[i];
! 474: }
! 475:
! 476: free(iter);
! 477: error_code = SSL_OK; /* got here - we are ok */
! 478:
! 479: error:
! 480: return error_code;
! 481: }
! 482:
! 483: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>