1214501Srpaulo/* 2214501Srpaulo * PKCS #8 (Private-key information syntax) 3214501Srpaulo * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "includes.h" 10214501Srpaulo 11214501Srpaulo#include "common.h" 12214501Srpaulo#include "asn1.h" 13214501Srpaulo#include "bignum.h" 14214501Srpaulo#include "rsa.h" 15214501Srpaulo#include "pkcs5.h" 16214501Srpaulo#include "pkcs8.h" 17214501Srpaulo 18214501Srpaulo 19214501Srpaulostruct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len) 20214501Srpaulo{ 21214501Srpaulo struct asn1_hdr hdr; 22214501Srpaulo const u8 *pos, *end; 23214501Srpaulo struct bignum *zero; 24214501Srpaulo struct asn1_oid oid; 25214501Srpaulo char obuf[80]; 26214501Srpaulo 27214501Srpaulo /* PKCS #8, Chapter 6 */ 28214501Srpaulo 29214501Srpaulo /* PrivateKeyInfo ::= SEQUENCE */ 30214501Srpaulo if (asn1_get_next(buf, len, &hdr) < 0 || 31214501Srpaulo hdr.class != ASN1_CLASS_UNIVERSAL || 32214501Srpaulo hdr.tag != ASN1_TAG_SEQUENCE) { 33214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 " 34214501Srpaulo "header (SEQUENCE); assume PKCS #8 not used"); 35214501Srpaulo return NULL; 36214501Srpaulo } 37214501Srpaulo pos = hdr.payload; 38214501Srpaulo end = pos + hdr.length; 39214501Srpaulo 40214501Srpaulo /* version Version (Version ::= INTEGER) */ 41214501Srpaulo if (asn1_get_next(pos, end - pos, &hdr) < 0 || 42214501Srpaulo hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { 43214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found " 44214501Srpaulo "class %d tag 0x%x; assume PKCS #8 not used", 45214501Srpaulo hdr.class, hdr.tag); 46214501Srpaulo return NULL; 47214501Srpaulo } 48214501Srpaulo 49214501Srpaulo zero = bignum_init(); 50214501Srpaulo if (zero == NULL) 51214501Srpaulo return NULL; 52214501Srpaulo 53214501Srpaulo if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) { 54214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER"); 55214501Srpaulo bignum_deinit(zero); 56214501Srpaulo return NULL; 57214501Srpaulo } 58214501Srpaulo pos = hdr.payload + hdr.length; 59214501Srpaulo 60214501Srpaulo if (bignum_cmp_d(zero, 0) != 0) { 61214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the " 62214501Srpaulo "beginning of private key; not found; assume " 63214501Srpaulo "PKCS #8 not used"); 64214501Srpaulo bignum_deinit(zero); 65214501Srpaulo return NULL; 66214501Srpaulo } 67214501Srpaulo bignum_deinit(zero); 68214501Srpaulo 69214501Srpaulo /* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier 70214501Srpaulo * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */ 71214501Srpaulo if (asn1_get_next(pos, len, &hdr) < 0 || 72214501Srpaulo hdr.class != ASN1_CLASS_UNIVERSAL || 73214501Srpaulo hdr.tag != ASN1_TAG_SEQUENCE) { 74214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE " 75214501Srpaulo "(AlgorithmIdentifier) - found class %d tag 0x%x; " 76214501Srpaulo "assume PKCS #8 not used", 77214501Srpaulo hdr.class, hdr.tag); 78214501Srpaulo return NULL; 79214501Srpaulo } 80214501Srpaulo 81214501Srpaulo if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) { 82214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID " 83214501Srpaulo "(algorithm); assume PKCS #8 not used"); 84214501Srpaulo return NULL; 85214501Srpaulo } 86214501Srpaulo 87214501Srpaulo asn1_oid_to_str(&oid, obuf, sizeof(obuf)); 88214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf); 89214501Srpaulo 90214501Srpaulo if (oid.len != 7 || 91214501Srpaulo oid.oid[0] != 1 /* iso */ || 92214501Srpaulo oid.oid[1] != 2 /* member-body */ || 93214501Srpaulo oid.oid[2] != 840 /* us */ || 94214501Srpaulo oid.oid[3] != 113549 /* rsadsi */ || 95214501Srpaulo oid.oid[4] != 1 /* pkcs */ || 96214501Srpaulo oid.oid[5] != 1 /* pkcs-1 */ || 97214501Srpaulo oid.oid[6] != 1 /* rsaEncryption */) { 98214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key " 99214501Srpaulo "algorithm %s", obuf); 100214501Srpaulo return NULL; 101214501Srpaulo } 102214501Srpaulo 103214501Srpaulo pos = hdr.payload + hdr.length; 104214501Srpaulo 105214501Srpaulo /* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */ 106214501Srpaulo if (asn1_get_next(pos, end - pos, &hdr) < 0 || 107214501Srpaulo hdr.class != ASN1_CLASS_UNIVERSAL || 108214501Srpaulo hdr.tag != ASN1_TAG_OCTETSTRING) { 109214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING " 110214501Srpaulo "(privateKey) - found class %d tag 0x%x", 111214501Srpaulo hdr.class, hdr.tag); 112214501Srpaulo return NULL; 113214501Srpaulo } 114214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey"); 115214501Srpaulo 116214501Srpaulo return (struct crypto_private_key *) 117214501Srpaulo crypto_rsa_import_private_key(hdr.payload, hdr.length); 118214501Srpaulo} 119214501Srpaulo 120214501Srpaulo 121214501Srpaulostruct crypto_private_key * 122214501Srpaulopkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd) 123214501Srpaulo{ 124214501Srpaulo struct asn1_hdr hdr; 125214501Srpaulo const u8 *pos, *end, *enc_alg; 126214501Srpaulo size_t enc_alg_len; 127214501Srpaulo u8 *data; 128214501Srpaulo size_t data_len; 129214501Srpaulo 130214501Srpaulo if (passwd == NULL) 131214501Srpaulo return NULL; 132214501Srpaulo 133214501Srpaulo /* 134214501Srpaulo * PKCS #8, Chapter 7 135214501Srpaulo * EncryptedPrivateKeyInfo ::= SEQUENCE { 136214501Srpaulo * encryptionAlgorithm EncryptionAlgorithmIdentifier, 137214501Srpaulo * encryptedData EncryptedData } 138214501Srpaulo * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier 139214501Srpaulo * EncryptedData ::= OCTET STRING 140214501Srpaulo */ 141214501Srpaulo 142214501Srpaulo if (asn1_get_next(buf, len, &hdr) < 0 || 143214501Srpaulo hdr.class != ASN1_CLASS_UNIVERSAL || 144214501Srpaulo hdr.tag != ASN1_TAG_SEQUENCE) { 145214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 " 146214501Srpaulo "header (SEQUENCE); assume encrypted PKCS #8 not " 147214501Srpaulo "used"); 148214501Srpaulo return NULL; 149214501Srpaulo } 150214501Srpaulo pos = hdr.payload; 151214501Srpaulo end = pos + hdr.length; 152214501Srpaulo 153214501Srpaulo /* encryptionAlgorithm EncryptionAlgorithmIdentifier */ 154214501Srpaulo if (asn1_get_next(pos, end - pos, &hdr) < 0 || 155214501Srpaulo hdr.class != ASN1_CLASS_UNIVERSAL || 156214501Srpaulo hdr.tag != ASN1_TAG_SEQUENCE) { 157214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE " 158214501Srpaulo "(AlgorithmIdentifier) - found class %d tag 0x%x; " 159214501Srpaulo "assume encrypted PKCS #8 not used", 160214501Srpaulo hdr.class, hdr.tag); 161214501Srpaulo return NULL; 162214501Srpaulo } 163214501Srpaulo enc_alg = hdr.payload; 164214501Srpaulo enc_alg_len = hdr.length; 165214501Srpaulo pos = hdr.payload + hdr.length; 166214501Srpaulo 167214501Srpaulo /* encryptedData EncryptedData */ 168214501Srpaulo if (asn1_get_next(pos, end - pos, &hdr) < 0 || 169214501Srpaulo hdr.class != ASN1_CLASS_UNIVERSAL || 170214501Srpaulo hdr.tag != ASN1_TAG_OCTETSTRING) { 171214501Srpaulo wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING " 172214501Srpaulo "(encryptedData) - found class %d tag 0x%x", 173214501Srpaulo hdr.class, hdr.tag); 174214501Srpaulo return NULL; 175214501Srpaulo } 176214501Srpaulo 177214501Srpaulo data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length, 178214501Srpaulo passwd, &data_len); 179214501Srpaulo if (data) { 180214501Srpaulo struct crypto_private_key *key; 181214501Srpaulo key = pkcs8_key_import(data, data_len); 182214501Srpaulo os_free(data); 183214501Srpaulo return key; 184214501Srpaulo } 185214501Srpaulo 186214501Srpaulo return NULL; 187214501Srpaulo} 188