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