18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * PKCS #8 (Private-key information syntax)
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "asn1.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "bignum.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "rsa.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "pkcs5.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "pkcs8.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct asn1_hdr hdr;
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end;
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct bignum *zero;
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct asn1_oid oid;
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char obuf[80];
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* PKCS #8, Chapter 6 */
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* PrivateKeyInfo ::= SEQUENCE */
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (asn1_get_next(buf, len, &hdr) < 0 ||
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.class != ASN1_CLASS_UNIVERSAL ||
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.tag != ASN1_TAG_SEQUENCE) {
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "header (SEQUENCE); assume PKCS #8 not used");
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = hdr.payload;
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = pos + hdr.length;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* version Version (Version ::= INTEGER) */
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found "
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "class %d tag 0x%x; assume PKCS #8 not used",
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   hdr.class, hdr.tag);
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	zero = bignum_init();
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (zero == NULL)
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) {
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER");
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bignum_deinit(zero);
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = hdr.payload + hdr.length;
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bignum_cmp_d(zero, 0) != 0) {
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the "
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "beginning of private key; not found; assume "
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "PKCS #8 not used");
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bignum_deinit(zero);
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bignum_deinit(zero);
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (asn1_get_next(pos, len, &hdr) < 0 ||
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.class != ASN1_CLASS_UNIVERSAL ||
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.tag != ASN1_TAG_SEQUENCE) {
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(AlgorithmIdentifier) - found class %d tag 0x%x; "
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "assume PKCS #8 not used",
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   hdr.class, hdr.tag);
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) {
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID "
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(algorithm); assume PKCS #8 not used");
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf);
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (oid.len != 7 ||
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    oid.oid[0] != 1 /* iso */ ||
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    oid.oid[1] != 2 /* member-body */ ||
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    oid.oid[2] != 840 /* us */ ||
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    oid.oid[3] != 113549 /* rsadsi */ ||
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    oid.oid[4] != 1 /* pkcs */ ||
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    oid.oid[5] != 1 /* pkcs-1 */ ||
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    oid.oid[6] != 1 /* rsaEncryption */) {
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key "
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "algorithm %s", obuf);
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = hdr.payload + hdr.length;
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.class != ASN1_CLASS_UNIVERSAL ||
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.tag != ASN1_TAG_OCTETSTRING) {
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(privateKey) - found class %d tag 0x%x",
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   hdr.class, hdr.tag);
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return (struct crypto_private_key *)
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		crypto_rsa_import_private_key(hdr.payload, hdr.length);
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct crypto_private_key *
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtpkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct asn1_hdr hdr;
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end, *enc_alg;
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t enc_alg_len;
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *data;
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t data_len;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (passwd == NULL)
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PKCS #8, Chapter 7
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * EncryptedPrivateKeyInfo ::= SEQUENCE {
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *   encryptionAlgorithm EncryptionAlgorithmIdentifier,
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *   encryptedData EncryptedData }
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * EncryptedData ::= OCTET STRING
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (asn1_get_next(buf, len, &hdr) < 0 ||
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.class != ASN1_CLASS_UNIVERSAL ||
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.tag != ASN1_TAG_SEQUENCE) {
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "header (SEQUENCE); assume encrypted PKCS #8 not "
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "used");
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = hdr.payload;
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = pos + hdr.length;
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* encryptionAlgorithm EncryptionAlgorithmIdentifier */
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.class != ASN1_CLASS_UNIVERSAL ||
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.tag != ASN1_TAG_SEQUENCE) {
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(AlgorithmIdentifier) - found class %d tag 0x%x; "
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "assume encrypted PKCS #8 not used",
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   hdr.class, hdr.tag);
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enc_alg = hdr.payload;
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enc_alg_len = hdr.length;
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = hdr.payload + hdr.length;
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* encryptedData EncryptedData */
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.class != ASN1_CLASS_UNIVERSAL ||
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.tag != ASN1_TAG_OCTETSTRING) {
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(encryptedData) - found class %d tag 0x%x",
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   hdr.class, hdr.tag);
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     passwd, &data_len);
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data) {
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct crypto_private_key *key;
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		key = pkcs8_key_import(data, data_len);
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(data);
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return key;
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
188