Rough and ready port of axTLS

Committer:
ashleymills
Date:
Mon May 13 18:15:18 2013 +0000
Revision:
0:5a29fd060ac8
initial commit

Who changed what in which revision?

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