TLS: Add minimal support for PKCS #12

This allows the internal TLS implementation to parse a private key and a
certificate from a PKCS #12 file protected with
pbeWithSHAAnd3-KeyTripleDES-CBC.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2015-12-13 20:52:43 +02:00
parent 5ce2941bfe
commit 6b7bb42923

View file

@ -1,6 +1,6 @@
/*
* TLSv1 credentials
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -11,6 +11,9 @@
#include "common.h"
#include "base64.h"
#include "crypto/crypto.h"
#include "crypto/sha1.h"
#include "pkcs5.h"
#include "pkcs8.h"
#include "x509v3.h"
#include "tlsv1_cred.h"
@ -325,6 +328,735 @@ static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
}
#ifdef PKCS12_FUNCS
static int oid_is_rsadsi(struct asn1_oid *oid)
{
return oid->len >= 4 &&
oid->oid[0] == 1 /* iso */ &&
oid->oid[1] == 2 /* member-body */ &&
oid->oid[2] == 840 /* us */ &&
oid->oid[3] == 113549 /* rsadsi */;
}
static int pkcs12_is_bagtype_oid(struct asn1_oid *oid, unsigned long type)
{
return oid->len == 9 &&
oid_is_rsadsi(oid) &&
oid->oid[4] == 1 /* pkcs */ &&
oid->oid[5] == 12 /* pkcs-12 */ &&
oid->oid[6] == 10 &&
oid->oid[7] == 1 /* bagtypes */ &&
oid->oid[8] == type;
}
static int is_oid_pkcs7(struct asn1_oid *oid)
{
return oid->len == 7 &&
oid->oid[0] == 1 /* iso */ &&
oid->oid[1] == 2 /* member-body */ &&
oid->oid[2] == 840 /* us */ &&
oid->oid[3] == 113549 /* rsadsi */ &&
oid->oid[4] == 1 /* pkcs */ &&
oid->oid[5] == 7 /* pkcs-7 */;
}
static int is_oid_pkcs7_data(struct asn1_oid *oid)
{
return is_oid_pkcs7(oid) && oid->oid[6] == 1 /* data */;
}
static int is_oid_pkcs7_enc_data(struct asn1_oid *oid)
{
return is_oid_pkcs7(oid) && oid->oid[6] == 6 /* encryptedData */;
}
static int is_oid_pkcs9(struct asn1_oid *oid)
{
return oid->len >= 6 &&
oid->oid[0] == 1 /* iso */ &&
oid->oid[1] == 2 /* member-body */ &&
oid->oid[2] == 840 /* us */ &&
oid->oid[3] == 113549 /* rsadsi */ &&
oid->oid[4] == 1 /* pkcs */ &&
oid->oid[5] == 9 /* pkcs-9 */;
}
static int is_oid_pkcs9_friendly_name(struct asn1_oid *oid)
{
return oid->len == 7 && is_oid_pkcs9(oid) &&
oid->oid[6] == 20;
}
static int is_oid_pkcs9_local_key_id(struct asn1_oid *oid)
{
return oid->len == 7 && is_oid_pkcs9(oid) &&
oid->oid[6] == 21;
}
static int is_oid_pkcs9_x509_cert(struct asn1_oid *oid)
{
return oid->len == 8 && is_oid_pkcs9(oid) &&
oid->oid[6] == 22 /* certTypes */ &&
oid->oid[7] == 1 /* x509Certificate */;
}
static int pkcs12_keybag(struct tlsv1_credentials *cred,
const u8 *buf, size_t len)
{
/* TODO */
return 0;
}
static int pkcs12_pkcs8_keybag(struct tlsv1_credentials *cred,
const u8 *buf, size_t len,
const char *passwd)
{
struct crypto_private_key *key;
/* PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo */
key = pkcs8_enc_key_import(buf, len, passwd);
if (!key)
return -1;
wpa_printf(MSG_DEBUG,
"PKCS #12: Successfully decrypted PKCS8ShroudedKeyBag");
crypto_private_key_free(cred->key);
cred->key = key;
return 0;
}
static int pkcs12_certbag(struct tlsv1_credentials *cred,
const u8 *buf, size_t len)
{
struct asn1_hdr hdr;
struct asn1_oid oid;
char obuf[80];
const u8 *pos, *end;
/*
* CertBag ::= SEQUENCE {
* certId BAG-TYPE.&id ({CertTypes}),
* certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId})
* }
*/
if (asn1_get_next(buf, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected SEQUENCE (CertBag) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
end = hdr.payload + hdr.length;
if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Failed to parse OID (certId)");
return -1;
}
asn1_oid_to_str(&oid, obuf, sizeof(obuf));
wpa_printf(MSG_DEBUG, "PKCS #12: certId %s", obuf);
if (!is_oid_pkcs9_x509_cert(&oid)) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Ignored unsupported certificate type (certId %s)",
obuf);
}
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
hdr.tag != 0) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected [0] EXPLICIT (certValue) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_OCTETSTRING) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected OCTET STRING (x509Certificate) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
wpa_hexdump(MSG_DEBUG, "PKCS #12: x509Certificate",
hdr.payload, hdr.length);
if (cred->cert) {
struct x509_certificate *cert;
wpa_printf(MSG_DEBUG, "PKCS #12: Ignore extra certificate");
cert = x509_certificate_parse(hdr.payload, hdr.length);
if (!cert) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Failed to parse x509Certificate");
return 0;
}
x509_certificate_chain_free(cert);
return 0;
}
return tlsv1_set_cert(cred, NULL, hdr.payload, hdr.length);
}
static int pkcs12_parse_attr_friendly_name(const u8 *pos, const u8 *end)
{
struct asn1_hdr hdr;
/*
* RFC 2985, 5.5.1:
* friendlyName ATTRIBUTE ::= {
* WITH SYNTAX BMPString (SIZE(1..pkcs-9-ub-friendlyName))
* EQUALITY MATCHING RULE caseIgnoreMatch
* SINGLE VALUE TRUE
* ID pkcs-9-at-friendlyName
* }
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_BMPSTRING) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected BMPSTRING (friendlyName) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return 0;
}
wpa_hexdump_ascii(MSG_DEBUG, "PKCS #12: friendlyName",
hdr.payload, hdr.length);
return 0;
}
static int pkcs12_parse_attr_local_key_id(const u8 *pos, const u8 *end)
{
struct asn1_hdr hdr;
/*
* RFC 2985, 5.5.2:
* localKeyId ATTRIBUTE ::= {
* WITH SYNTAX OCTET STRING
* EQUALITY MATCHING RULE octetStringMatch
* SINGLE VALUE TRUE
* ID pkcs-9-at-localKeyId
* }
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_OCTETSTRING) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected OCTET STRING (localKeyID) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "PKCS #12: localKeyID",
hdr.payload, hdr.length);
return 0;
}
static int pkcs12_parse_attr(const u8 *pos, size_t len)
{
const u8 *end = pos + len;
struct asn1_hdr hdr;
struct asn1_oid a_oid;
char obuf[80];
/*
* PKCS12Attribute ::= SEQUENCE {
* attrId ATTRIBUTE.&id ({PKCS12AttrSet}),
* attrValues SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId})
* }
*/
if (asn1_get_oid(pos, end - pos, &a_oid, &pos)) {
wpa_printf(MSG_DEBUG, "PKCS #12: Failed to parse OID (attrId)");
return -1;
}
asn1_oid_to_str(&a_oid, obuf, sizeof(obuf));
wpa_printf(MSG_DEBUG, "PKCS #12: attrId %s", obuf);
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SET) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected SET (attrValues) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: attrValues",
hdr.payload, hdr.length);
pos = hdr.payload;
end = hdr.payload + hdr.length;
if (is_oid_pkcs9_friendly_name(&a_oid))
return pkcs12_parse_attr_friendly_name(pos, end);
if (is_oid_pkcs9_local_key_id(&a_oid))
return pkcs12_parse_attr_local_key_id(pos, end);
wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unknown attribute");
return 0;
}
static int pkcs12_safebag(struct tlsv1_credentials *cred,
const u8 *buf, size_t len, const char *passwd)
{
struct asn1_hdr hdr;
struct asn1_oid oid;
char obuf[80];
const u8 *pos = buf, *end = buf + len;
const u8 *value;
size_t value_len;
wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: SafeBag", buf, len);
/* BAG-TYPE ::= TYPE-IDENTIFIER */
if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Failed to parse OID (BAG-TYPE)");
return -1;
}
asn1_oid_to_str(&oid, obuf, sizeof(obuf));
wpa_printf(MSG_DEBUG, "PKCS #12: BAG-TYPE %s", obuf);
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
hdr.tag != 0) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected [0] EXPLICIT (bagValue) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return 0;
}
value = hdr.payload;
value_len = hdr.length;
wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagValue", value, value_len);
pos = hdr.payload + hdr.length;
if (pos < end) {
/* bagAttributes SET OF PKCS12Attribute OPTIONAL */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SET) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected SET (bagAttributes) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagAttributes",
hdr.payload, hdr.length);
pos = hdr.payload;
end = hdr.payload + hdr.length;
while (pos < end) {
/* PKCS12Attribute ::= SEQUENCE */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected SEQUENCE (PKCS12Attribute) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
if (pkcs12_parse_attr(hdr.payload, hdr.length) < 0)
return -1;
pos = hdr.payload + hdr.length;
}
}
if (pkcs12_is_bagtype_oid(&oid, 1))
return pkcs12_keybag(cred, value, value_len);
if (pkcs12_is_bagtype_oid(&oid, 2))
return pkcs12_pkcs8_keybag(cred, value, value_len, passwd);
if (pkcs12_is_bagtype_oid(&oid, 3))
return pkcs12_certbag(cred, value, value_len);
wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unsupported BAG-TYPE");
return 0;
}
static int pkcs12_safecontents(struct tlsv1_credentials *cred,
const u8 *buf, size_t len,
const char *passwd)
{
struct asn1_hdr hdr;
const u8 *pos, *end;
/* SafeContents ::= SEQUENCE OF SafeBag */
if (asn1_get_next(buf, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected SEQUENCE (SafeContents) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
end = hdr.payload + hdr.length;
/*
* SafeBag ::= SEQUENCE {
* bagId BAG-TYPE.&id ({PKCS12BagSet})
* bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
* bagAttributes SET OF PKCS12Attribute OPTIONAL
* }
*/
while (pos < end) {
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected SEQUENCE (SafeBag) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
if (pkcs12_safebag(cred, hdr.payload, hdr.length, passwd) < 0)
return -1;
pos = hdr.payload + hdr.length;
}
return 0;
}
static int pkcs12_parse_content_data(struct tlsv1_credentials *cred,
const u8 *pos, const u8 *end,
const char *passwd)
{
struct asn1_hdr hdr;
/* Data ::= OCTET STRING */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_OCTETSTRING) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected OCTET STRING (Data) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data", hdr.payload, hdr.length);
return pkcs12_safecontents(cred, hdr.payload, hdr.length, passwd);
}
static int pkcs12_parse_content_enc_data(struct tlsv1_credentials *cred,
const u8 *pos, const u8 *end,
const char *passwd)
{
struct asn1_hdr hdr;
struct asn1_oid oid;
char buf[80];
const u8 *enc_alg;
u8 *data;
size_t enc_alg_len, data_len;
int res = -1;
/*
* EncryptedData ::= SEQUENCE {
* version Version,
* encryptedContentInfo EncryptedContentInfo }
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected SEQUENCE (EncryptedData) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return 0;
}
pos = hdr.payload;
/* Version ::= INTEGER */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
wpa_printf(MSG_DEBUG,
"PKCS #12: No INTEGER tag found for version; class=%d tag=0x%x",
hdr.class, hdr.tag);
return -1;
}
if (hdr.length != 1 || hdr.payload[0] != 0) {
wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized PKCS #7 version");
return -1;
}
pos = hdr.payload + hdr.length;
wpa_hexdump(MSG_MSGDUMP, "PKCS #12: EncryptedContentInfo",
pos, end - pos);
/*
* EncryptedContentInfo ::= SEQUENCE {
* contentType ContentType,
* contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL }
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected SEQUENCE (EncryptedContentInfo) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
end = pos + hdr.length;
/* ContentType ::= OBJECT IDENTIFIER */
if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
return -1;
}
asn1_oid_to_str(&oid, buf, sizeof(buf));
wpa_printf(MSG_DEBUG, "PKCS #12: EncryptedContentInfo::contentType %s",
buf);
if (!is_oid_pkcs7_data(&oid)) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Unsupported EncryptedContentInfo::contentType %s",
buf);
return 0;
}
/* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "PKCS #12: Expected SEQUENCE (ContentEncryptionAlgorithmIdentifier) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
enc_alg = hdr.payload;
enc_alg_len = hdr.length;
pos = hdr.payload + hdr.length;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
hdr.tag != 0) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected [0] IMPLICIT (encryptedContent) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
/* EncryptedContent ::= OCTET STRING */
data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
passwd, &data_len);
if (data) {
wpa_hexdump_key(MSG_MSGDUMP,
"PKCS #12: Decrypted encryptedContent",
data, data_len);
res = pkcs12_safecontents(cred, data, data_len, passwd);
os_free(data);
}
return res;
}
static int pkcs12_parse_content(struct tlsv1_credentials *cred,
const u8 *buf, size_t len,
const char *passwd)
{
const u8 *pos = buf;
const u8 *end = buf + len;
struct asn1_oid oid;
char txt[80];
struct asn1_hdr hdr;
wpa_hexdump(MSG_MSGDUMP, "PKCS #12: ContentInfo", buf, len);
if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
return 0;
}
asn1_oid_to_str(&oid, txt, sizeof(txt));
wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", txt);
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
hdr.tag != 0) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected [0] EXPLICIT (content) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return 0;
}
pos = hdr.payload;
if (is_oid_pkcs7_data(&oid))
return pkcs12_parse_content_data(cred, pos, end, passwd);
if (is_oid_pkcs7_enc_data(&oid))
return pkcs12_parse_content_enc_data(cred, pos, end, passwd);
wpa_printf(MSG_DEBUG, "PKCS #12: Ignored unsupported contentType %s",
txt);
return 0;
}
static int pkcs12_parse(struct tlsv1_credentials *cred,
const u8 *key, size_t len, const char *passwd)
{
struct asn1_hdr hdr;
const u8 *pos, *end;
struct asn1_oid oid;
char buf[80];
/*
* PFX ::= SEQUENCE {
* version INTEGER {v3(3)}(v3,...),
* authSafe ContentInfo,
* macData MacData OPTIONAL
* }
*/
if (asn1_get_next(key, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected SEQUENCE (PFX) - found class %d tag 0x%x; assume PKCS #12 not used",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
end = pos + hdr.length;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
wpa_printf(MSG_DEBUG,
"PKCS #12: No INTEGER tag found for version; class=%d tag=0x%x",
hdr.class, hdr.tag);
return -1;
}
if (hdr.length != 1 || hdr.payload[0] != 3) {
wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized version");
return -1;
}
pos = hdr.payload + hdr.length;
/*
* ContentInfo ::= SEQUENCE {
* contentType ContentType,
* content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected SEQUENCE (authSafe) - found class %d tag 0x%x; assume PKCS #12 not used",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
end = pos + hdr.length;
/* ContentType ::= OBJECT IDENTIFIER */
if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Could not find OBJECT IDENTIFIER (contentType); assume PKCS #12 not used");
return -1;
}
asn1_oid_to_str(&oid, buf, sizeof(buf));
wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", buf);
if (!is_oid_pkcs7_data(&oid)) {
wpa_printf(MSG_DEBUG, "PKCS #12: Unsupported contentType %s",
buf);
return -1;
}
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
hdr.tag != 0) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected [0] EXPLICIT (content) - found class %d tag 0x%x; assume PKCS #12 not used",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
/* Data ::= OCTET STRING */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_OCTETSTRING) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected OCTET STRING (Data) - found class %d tag 0x%x; assume PKCS #12 not used",
hdr.class, hdr.tag);
return -1;
}
/*
* AuthenticatedSafe ::= SEQUENCE OF ContentInfo
* -- Data if unencrypted
* -- EncryptedData if password-encrypted
* -- EnvelopedData if public key-encrypted
*/
wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data content",
hdr.payload, hdr.length);
if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected SEQUENCE within Data content - found class %d tag 0x%x; assume PKCS #12 not used",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
end = pos + hdr.length;
while (end > pos) {
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG,
"PKCS #12: Expected SEQUENCE (ContentInfo) - found class %d tag 0x%x; assume PKCS #12 not used",
hdr.class, hdr.tag);
return -1;
}
if (pkcs12_parse_content(cred, hdr.payload, hdr.length,
passwd) < 0)
return -1;
pos = hdr.payload + hdr.length;
}
return 0;
}
#endif /* PKCS12_FUNCS */
static int tlsv1_set_key(struct tlsv1_credentials *cred,
const u8 *key, size_t len, const char *passwd)
{
@ -333,6 +1065,10 @@ static int tlsv1_set_key(struct tlsv1_credentials *cred,
cred->key = tlsv1_set_key_pem(key, len);
if (cred->key == NULL)
cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
#ifdef PKCS12_FUNCS
if (!cred->key)
pkcs12_parse(cred, key, len, passwd);
#endif /* PKCS12_FUNCS */
if (cred->key == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
return -1;