Home | History | Annotate | Download | only in tls
      1 /*
      2  * PKCS #8 (Private-key information syntax)
      3  * Copyright (c) 2006-2009, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include "includes.h"
     16 
     17 #include "common.h"
     18 #include "asn1.h"
     19 #include "bignum.h"
     20 #include "rsa.h"
     21 #include "pkcs5.h"
     22 #include "pkcs8.h"
     23 
     24 
     25 struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
     26 {
     27 	struct asn1_hdr hdr;
     28 	const u8 *pos, *end;
     29 	struct bignum *zero;
     30 	struct asn1_oid oid;
     31 	char obuf[80];
     32 
     33 	/* PKCS #8, Chapter 6 */
     34 
     35 	/* PrivateKeyInfo ::= SEQUENCE */
     36 	if (asn1_get_next(buf, len, &hdr) < 0 ||
     37 	    hdr.class != ASN1_CLASS_UNIVERSAL ||
     38 	    hdr.tag != ASN1_TAG_SEQUENCE) {
     39 		wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
     40 			   "header (SEQUENCE); assume PKCS #8 not used");
     41 		return NULL;
     42 	}
     43 	pos = hdr.payload;
     44 	end = pos + hdr.length;
     45 
     46 	/* version Version (Version ::= INTEGER) */
     47 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
     48 	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
     49 		wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found "
     50 			   "class %d tag 0x%x; assume PKCS #8 not used",
     51 			   hdr.class, hdr.tag);
     52 		return NULL;
     53 	}
     54 
     55 	zero = bignum_init();
     56 	if (zero == NULL)
     57 		return NULL;
     58 
     59 	if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) {
     60 		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER");
     61 		bignum_deinit(zero);
     62 		return NULL;
     63 	}
     64 	pos = hdr.payload + hdr.length;
     65 
     66 	if (bignum_cmp_d(zero, 0) != 0) {
     67 		wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the "
     68 			   "beginning of private key; not found; assume "
     69 			   "PKCS #8 not used");
     70 		bignum_deinit(zero);
     71 		return NULL;
     72 	}
     73 	bignum_deinit(zero);
     74 
     75 	/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
     76 	 * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
     77 	if (asn1_get_next(pos, len, &hdr) < 0 ||
     78 	    hdr.class != ASN1_CLASS_UNIVERSAL ||
     79 	    hdr.tag != ASN1_TAG_SEQUENCE) {
     80 		wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
     81 			   "(AlgorithmIdentifier) - found class %d tag 0x%x; "
     82 			   "assume PKCS #8 not used",
     83 			   hdr.class, hdr.tag);
     84 		return NULL;
     85 	}
     86 
     87 	if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) {
     88 		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID "
     89 			   "(algorithm); assume PKCS #8 not used");
     90 		return NULL;
     91 	}
     92 
     93 	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
     94 	wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf);
     95 
     96 	if (oid.len != 7 ||
     97 	    oid.oid[0] != 1 /* iso */ ||
     98 	    oid.oid[1] != 2 /* member-body */ ||
     99 	    oid.oid[2] != 840 /* us */ ||
    100 	    oid.oid[3] != 113549 /* rsadsi */ ||
    101 	    oid.oid[4] != 1 /* pkcs */ ||
    102 	    oid.oid[5] != 1 /* pkcs-1 */ ||
    103 	    oid.oid[6] != 1 /* rsaEncryption */) {
    104 		wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key "
    105 			   "algorithm %s", obuf);
    106 		return NULL;
    107 	}
    108 
    109 	pos = hdr.payload + hdr.length;
    110 
    111 	/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
    112 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
    113 	    hdr.class != ASN1_CLASS_UNIVERSAL ||
    114 	    hdr.tag != ASN1_TAG_OCTETSTRING) {
    115 		wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
    116 			   "(privateKey) - found class %d tag 0x%x",
    117 			   hdr.class, hdr.tag);
    118 		return NULL;
    119 	}
    120 	wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
    121 
    122 	return (struct crypto_private_key *)
    123 		crypto_rsa_import_private_key(hdr.payload, hdr.length);
    124 }
    125 
    126 
    127 struct crypto_private_key *
    128 pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
    129 {
    130 	struct asn1_hdr hdr;
    131 	const u8 *pos, *end, *enc_alg;
    132 	size_t enc_alg_len;
    133 	u8 *data;
    134 	size_t data_len;
    135 
    136 	if (passwd == NULL)
    137 		return NULL;
    138 
    139 	/*
    140 	 * PKCS #8, Chapter 7
    141 	 * EncryptedPrivateKeyInfo ::= SEQUENCE {
    142 	 *   encryptionAlgorithm EncryptionAlgorithmIdentifier,
    143 	 *   encryptedData EncryptedData }
    144 	 * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
    145 	 * EncryptedData ::= OCTET STRING
    146 	 */
    147 
    148 	if (asn1_get_next(buf, len, &hdr) < 0 ||
    149 	    hdr.class != ASN1_CLASS_UNIVERSAL ||
    150 	    hdr.tag != ASN1_TAG_SEQUENCE) {
    151 		wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
    152 			   "header (SEQUENCE); assume encrypted PKCS #8 not "
    153 			   "used");
    154 		return NULL;
    155 	}
    156 	pos = hdr.payload;
    157 	end = pos + hdr.length;
    158 
    159 	/* encryptionAlgorithm EncryptionAlgorithmIdentifier */
    160 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
    161 	    hdr.class != ASN1_CLASS_UNIVERSAL ||
    162 	    hdr.tag != ASN1_TAG_SEQUENCE) {
    163 		wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
    164 			   "(AlgorithmIdentifier) - found class %d tag 0x%x; "
    165 			   "assume encrypted PKCS #8 not used",
    166 			   hdr.class, hdr.tag);
    167 		return NULL;
    168 	}
    169 	enc_alg = hdr.payload;
    170 	enc_alg_len = hdr.length;
    171 	pos = hdr.payload + hdr.length;
    172 
    173 	/* encryptedData EncryptedData */
    174 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
    175 	    hdr.class != ASN1_CLASS_UNIVERSAL ||
    176 	    hdr.tag != ASN1_TAG_OCTETSTRING) {
    177 		wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
    178 			   "(encryptedData) - found class %d tag 0x%x",
    179 			   hdr.class, hdr.tag);
    180 		return NULL;
    181 	}
    182 
    183 	data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
    184 			     passwd, &data_len);
    185 	if (data) {
    186 		struct crypto_private_key *key;
    187 		key = pkcs8_key_import(data, data_len);
    188 		os_free(data);
    189 		return key;
    190 	}
    191 
    192 	return NULL;
    193 }
    194