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