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