[tls] Add full X.509 certificate parsing
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
parent
d6979e0d55
commit
4d3b5473f8
50
src/crypto/rootcert.c
Normal file
50
src/crypto/rootcert.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/sha256.h>
|
||||
#include <ipxe/x509.h>
|
||||
#include <ipxe/rootcert.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Root certificate store
|
||||
*
|
||||
*/
|
||||
|
||||
/* Use iPXE root CA if no trusted certificates are explicitly specified */
|
||||
#ifndef TRUSTED
|
||||
#define TRUSTED \
|
||||
/* iPXE root CA */ \
|
||||
0x9f, 0xaf, 0x71, 0x7b, 0x7f, 0x8c, 0xa2, 0xf9, 0x3c, 0x25, \
|
||||
0x6c, 0x79, 0xf8, 0xac, 0x55, 0x91, 0x89, 0x5d, 0x66, 0xd1, \
|
||||
0xff, 0x3b, 0xee, 0x63, 0x97, 0xa7, 0x0d, 0x29, 0xc6, 0x5e, \
|
||||
0xed, 0x1a,
|
||||
#endif
|
||||
|
||||
/** Root certificate fingerprints */
|
||||
static const uint8_t fingerprints[] = { TRUSTED };
|
||||
|
||||
/** Root certificates */
|
||||
struct x509_root root_certificates = {
|
||||
.digest = &sha256_algorithm,
|
||||
.count = ( sizeof ( fingerprints ) / SHA256_DIGEST_SIZE ),
|
||||
.fingerprints = fingerprints,
|
||||
};
|
1179
src/crypto/x509.c
1179
src/crypto/x509.c
File diff suppressed because it is too large
Load Diff
16
src/include/ipxe/rootcert.h
Normal file
16
src/include/ipxe/rootcert.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef _IPXE_ROOTCERT_H
|
||||
#define _IPXE_ROOTCERT_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Root certificate store
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <ipxe/x509.h>
|
||||
|
||||
extern struct x509_root root_certificates;
|
||||
|
||||
#endif /* _IPXE_ROOTCERT_H */
|
@ -10,16 +10,220 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <ipxe/asn1.h>
|
||||
|
||||
/** An X.509 RSA public key */
|
||||
struct x509_rsa_public_key {
|
||||
/** Raw public key */
|
||||
/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) */
|
||||
#define ASN1_OID_ATTRIBUTE_TYPE \
|
||||
ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 4 )
|
||||
|
||||
/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) commonName(3) */
|
||||
#define ASN1_OID_COMMON_NAME ASN1_OID_ATTRIBUTE_TYPE, ASN1_OID_SINGLE ( 3 )
|
||||
|
||||
/** ASN.1 OID for id-ce */
|
||||
#define ASN1_OID_CE ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 29 )
|
||||
|
||||
/** ASN.1 OID for id-ce-keyUsage */
|
||||
#define ASN1_OID_KEYUSAGE ASN1_OID_CE, ASN1_OID_SINGLE ( 15 )
|
||||
|
||||
/** ASN.1 OID for id-ce-basicConstraints */
|
||||
#define ASN1_OID_BASICCONSTRAINTS ASN1_OID_CE, ASN1_OID_SINGLE ( 19 )
|
||||
|
||||
/** An X.509 algorithm */
|
||||
struct x509_algorithm {
|
||||
/** Name */
|
||||
const char *name;
|
||||
/** Object identifier */
|
||||
struct asn1_cursor oid;
|
||||
/** Public-key algorithm */
|
||||
struct pubkey_algorithm *pubkey;
|
||||
/** Digest algorithm (if applicable) */
|
||||
struct digest_algorithm *digest;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test if X.509 algorithm is a signature algorithm
|
||||
*
|
||||
* @v algorithm Algorithm
|
||||
* @ret is_signature Algorithm is a signature algorithm
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int
|
||||
x509_is_signature_algorithm ( struct x509_algorithm *algorithm ) {
|
||||
return ( algorithm->digest != NULL );
|
||||
}
|
||||
|
||||
/** An X.509 bit string */
|
||||
struct x509_bit_string {
|
||||
/** Data */
|
||||
const void *data;
|
||||
/** Length */
|
||||
size_t len;
|
||||
/** Unused bits at end of data */
|
||||
unsigned int unused;
|
||||
};
|
||||
|
||||
/** An X.509 issuer */
|
||||
struct x509_issuer {
|
||||
/** Raw issuer */
|
||||
struct asn1_cursor raw;
|
||||
};
|
||||
|
||||
extern int x509_rsa_public_key ( const struct asn1_cursor *certificate,
|
||||
struct x509_rsa_public_key *rsa_pubkey );
|
||||
/** An X.509 time */
|
||||
struct x509_time {
|
||||
/** Year */
|
||||
uint16_t year;
|
||||
/** Month */
|
||||
uint8_t month;
|
||||
/** Day */
|
||||
uint8_t day;
|
||||
/** Hour */
|
||||
uint8_t hour;
|
||||
/** Minute */
|
||||
uint8_t minute;
|
||||
/** Second */
|
||||
uint8_t second;
|
||||
};
|
||||
|
||||
/** An X.509 certificate validity period */
|
||||
struct x509_validity {
|
||||
/** Not valid before */
|
||||
struct x509_time not_before;
|
||||
/** Not valid after */
|
||||
struct x509_time not_after;
|
||||
};
|
||||
|
||||
/** An X.509 name */
|
||||
struct x509_name {
|
||||
/** Name (not NUL-terminated) */
|
||||
const void *data;
|
||||
/** Length of name */
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/** An X.509 certificate public key */
|
||||
struct x509_public_key {
|
||||
/** Raw public key */
|
||||
struct asn1_cursor raw;
|
||||
/** Public key algorithm */
|
||||
struct x509_algorithm *algorithm;
|
||||
};
|
||||
|
||||
/** An X.509 certificate subject */
|
||||
struct x509_subject {
|
||||
/** Raw subject */
|
||||
struct asn1_cursor raw;
|
||||
/** Common name */
|
||||
struct x509_name name;
|
||||
/** Public key information */
|
||||
struct x509_public_key public_key;
|
||||
};
|
||||
|
||||
/** An X.509 certificate signature */
|
||||
struct x509_signature {
|
||||
/** Signature algorithm */
|
||||
struct x509_algorithm *algorithm;
|
||||
/** Signature value */
|
||||
struct x509_bit_string value;
|
||||
};
|
||||
|
||||
/** An X.509 certificate basic constraints set */
|
||||
struct x509_basic_constraints {
|
||||
/** Subject is a CA */
|
||||
int ca;
|
||||
/** Path length */
|
||||
unsigned int path_len;
|
||||
};
|
||||
|
||||
/** An X.509 certificate key usage */
|
||||
struct x509_key_usage {
|
||||
/** Key usage extension is present */
|
||||
int present;
|
||||
/** Usage bits */
|
||||
unsigned int bits;
|
||||
};
|
||||
|
||||
/** X.509 certificate key usage bits */
|
||||
enum x509_key_usage_bits {
|
||||
X509_DIGITAL_SIGNATURE = 0x0080,
|
||||
X509_NON_REPUDIATION = 0x0040,
|
||||
X509_KEY_ENCIPHERMENT = 0x0020,
|
||||
X509_DATA_ENCIPHERMENT = 0x0010,
|
||||
X509_KEY_AGREEMENT = 0x0008,
|
||||
X509_KEY_CERT_SIGN = 0x0004,
|
||||
X509_CRL_SIGN = 0x0002,
|
||||
X509_ENCIPHER_ONLY = 0x0001,
|
||||
X509_DECIPHER_ONLY = 0x8000,
|
||||
};
|
||||
|
||||
/** An X.509 certificate extensions set */
|
||||
struct x509_extensions {
|
||||
/** Basic constraints */
|
||||
struct x509_basic_constraints basic;
|
||||
/** Key usage */
|
||||
struct x509_key_usage usage;
|
||||
};
|
||||
|
||||
/** An X.509 certificate */
|
||||
struct x509_certificate {
|
||||
/** Raw certificate */
|
||||
struct asn1_cursor raw;
|
||||
/** Version */
|
||||
unsigned int version;
|
||||
/** Raw tbsCertificate */
|
||||
struct asn1_cursor tbs;
|
||||
/** Signature algorithm */
|
||||
struct x509_algorithm *signature_algorithm;
|
||||
/** Issuer */
|
||||
struct x509_issuer issuer;
|
||||
/** Validity */
|
||||
struct x509_validity validity;
|
||||
/** Subject */
|
||||
struct x509_subject subject;
|
||||
/** Signature */
|
||||
struct x509_signature signature;
|
||||
/** Extensions */
|
||||
struct x509_extensions extensions;
|
||||
};
|
||||
|
||||
/** An X.509 extension */
|
||||
struct x509_extension {
|
||||
/** Name */
|
||||
const char *name;
|
||||
/** Object identifier */
|
||||
struct asn1_cursor oid;
|
||||
/** Parse extension
|
||||
*
|
||||
* @v cert X.509 certificate
|
||||
* @v raw ASN.1 cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int ( * parse ) ( struct x509_certificate *cert,
|
||||
const struct asn1_cursor *raw );
|
||||
};
|
||||
|
||||
/** An X.509 root certificate store */
|
||||
struct x509_root {
|
||||
/** Fingerprint digest algorithm */
|
||||
struct digest_algorithm *digest;
|
||||
/** Number of certificates */
|
||||
unsigned int count;
|
||||
/** Certificate fingerprints */
|
||||
const void *fingerprints;
|
||||
};
|
||||
|
||||
extern int x509_parse ( struct x509_certificate *cert,
|
||||
const void *data, size_t len );
|
||||
extern int x509_validate ( struct x509_certificate *cert,
|
||||
struct x509_certificate *issuer );
|
||||
extern void x509_fingerprint ( struct x509_certificate *cert,
|
||||
struct digest_algorithm *digest,
|
||||
void *fingerprint );
|
||||
extern int x509_validate_root ( struct x509_certificate *cert,
|
||||
struct x509_root *root );
|
||||
extern int x509_validate_chain ( int ( * parse_next )
|
||||
( struct x509_certificate *cert,
|
||||
void *context ),
|
||||
void *context, struct x509_root *root,
|
||||
struct x509_certificate *first );
|
||||
|
||||
#endif /* _IPXE_X509_H */
|
||||
|
@ -1026,8 +1026,10 @@ static int tls_new_certificate ( struct tls_session *tls,
|
||||
const void *end = ( certificate->certificates + elements_len );
|
||||
struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
|
||||
struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
|
||||
struct asn1_cursor cursor;
|
||||
struct x509_rsa_public_key key;
|
||||
struct x509_certificate cert;
|
||||
struct x509_public_key *key = &cert.subject.public_key;
|
||||
const void *cert_data;
|
||||
size_t cert_len;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
@ -1040,9 +1042,9 @@ static int tls_new_certificate ( struct tls_session *tls,
|
||||
|
||||
/* Traverse certificate chain */
|
||||
do {
|
||||
cursor.data = element->certificate;
|
||||
cursor.len = tls_uint24 ( element->length );
|
||||
if ( ( cursor.data + cursor.len ) > end ) {
|
||||
cert_data = element->certificate;
|
||||
cert_len = tls_uint24 ( element->length );
|
||||
if ( ( cert_data + cert_len ) > end ) {
|
||||
DBGC ( tls, "TLS %p received corrupt Server "
|
||||
"Certificate\n", tls );
|
||||
DBGC_HD ( tls, data, len );
|
||||
@ -1050,23 +1052,23 @@ static int tls_new_certificate ( struct tls_session *tls,
|
||||
}
|
||||
|
||||
// HACK
|
||||
if ( ( rc = x509_rsa_public_key ( &cursor, &key ) ) != 0 ) {
|
||||
DBGC ( tls, "TLS %p cannot parse public key: %s\n",
|
||||
|
||||
/* Parse certificate */
|
||||
if ( ( rc = x509_parse ( &cert, cert_data, cert_len ) ) != 0 ) {
|
||||
DBGC ( tls, "TLS %p cannot parse certificate: %s\n",
|
||||
tls, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Initialise public key algorithm */
|
||||
if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx,
|
||||
key.raw.data, key.raw.len ) ) != 0){
|
||||
key->raw.data, key->raw.len ) ) != 0){
|
||||
DBGC ( tls, "TLS %p cannot initialise public key: %s\n",
|
||||
tls, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
element = ( cursor.data + cursor.len );
|
||||
} while ( element != end );
|
||||
|
||||
return -EINVAL;
|
||||
|
Reference in New Issue
Block a user