summaryrefslogtreecommitdiffstats
path: root/src/crypto/x509.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/x509.c')
-rw-r--r--src/crypto/x509.c202
1 files changed, 159 insertions, 43 deletions
diff --git a/src/crypto/x509.c b/src/crypto/x509.c
index 92318093e..6a3fe423b 100644
--- a/src/crypto/x509.c
+++ b/src/crypto/x509.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdlib.h>
#include <string.h>
@@ -38,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/rsa.h>
#include <ipxe/rootcert.h>
#include <ipxe/certstore.h>
+#include <ipxe/privkey.h>
#include <ipxe/socket.h>
#include <ipxe/in.h>
#include <ipxe/image.h>
@@ -231,7 +233,7 @@ static int x509_parse_serial ( struct x509_certificate *cert,
cert, strerror ( rc ) );
return rc;
}
- DBGC2 ( cert, "X509 %p issuer is:\n", cert );
+ DBGC2 ( cert, "X509 %p serial is:\n", cert );
DBGC2_HDA ( cert, 0, serial->raw.data, serial->raw.len );
return 0;
@@ -391,7 +393,7 @@ static int x509_parse_public_key ( struct x509_certificate *cert,
const struct asn1_cursor *raw ) {
struct x509_public_key *public_key = &cert->subject.public_key;
struct asn1_algorithm **algorithm = &public_key->algorithm;
- struct asn1_bit_string *raw_bits = &public_key->raw_bits;
+ struct asn1_cursor *value = &public_key->value;
struct asn1_cursor cursor;
int rc;
@@ -415,8 +417,9 @@ static int x509_parse_public_key ( struct x509_certificate *cert,
cert, (*algorithm)->name );
asn1_skip_any ( &cursor );
- /* Parse bit string */
- if ( ( rc = asn1_bit_string ( &cursor, raw_bits ) ) != 0 ) {
+ /* Parse subjectPublicKey */
+ memcpy ( value, &cursor, sizeof ( *value ) );
+ if ( ( rc = asn1_enter_bits ( value, NULL ) ) != 0 ) {
DBGC ( cert, "X509 %p could not parse public key bits: %s\n",
cert, strerror ( rc ) );
return rc;
@@ -497,8 +500,9 @@ static int x509_parse_basic_constraints ( struct x509_certificate *cert,
static int x509_parse_key_usage ( struct x509_certificate *cert,
const struct asn1_cursor *raw ) {
struct x509_key_usage *usage = &cert->extensions.usage;
- struct asn1_bit_string bit_string;
+ struct asn1_cursor cursor;
const uint8_t *bytes;
+ unsigned int unused;
size_t len;
unsigned int i;
int rc;
@@ -506,16 +510,17 @@ static int x509_parse_key_usage ( struct x509_certificate *cert,
/* Mark extension as present */
usage->present = 1;
- /* Parse bit string */
- if ( ( rc = asn1_bit_string ( raw, &bit_string ) ) != 0 ) {
+ /* Enter bit string */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ if ( ( rc = asn1_enter_bits ( &cursor, &unused ) ) != 0 ) {
DBGC ( cert, "X509 %p could not parse key usage: %s\n",
cert, strerror ( rc ) );
return rc;
}
/* Parse key usage bits */
- bytes = bit_string.data;
- len = bit_string.len;
+ bytes = cursor.data;
+ len = cursor.len;
if ( len > sizeof ( usage->bits ) )
len = sizeof ( usage->bits );
for ( i = 0 ; i < len ; i++ ) {
@@ -1004,7 +1009,7 @@ int x509_parse ( struct x509_certificate *cert,
const struct asn1_cursor *raw ) {
struct x509_signature *signature = &cert->signature;
struct asn1_algorithm **signature_algorithm = &signature->algorithm;
- struct asn1_bit_string *signature_value = &signature->value;
+ struct asn1_cursor *signature_value = &signature->value;
struct asn1_cursor cursor;
int rc;
@@ -1032,8 +1037,8 @@ int x509_parse ( struct x509_certificate *cert,
asn1_skip_any ( &cursor );
/* Parse signatureValue */
- if ( ( rc = asn1_integral_bit_string ( &cursor,
- signature_value ) ) != 0 ) {
+ memcpy ( signature_value, &cursor, sizeof ( *signature_value ) );
+ if ( ( rc = asn1_enter_bits ( signature_value, NULL ) ) != 0 ) {
DBGC ( cert, "X509 %p could not parse signature value: %s\n",
cert, strerror ( rc ) );
return rc;
@@ -1078,7 +1083,7 @@ int x509_certificate ( const void *data, size_t len,
asn1_shrink_any ( &cursor );
/* Return stored certificate, if present */
- if ( ( *cert = certstore_find ( &cursor ) ) != NULL ) {
+ if ( ( *cert = x509_find ( NULL, &cursor ) ) != NULL ) {
/* Add caller's reference */
x509_get ( *cert );
@@ -1124,7 +1129,6 @@ static int x509_check_signature ( struct x509_certificate *cert,
struct pubkey_algorithm *pubkey = algorithm->pubkey;
uint8_t digest_ctx[ digest->ctxsize ];
uint8_t digest_out[ digest->digestsize ];
- uint8_t pubkey_ctx[ pubkey->ctxsize ];
int rc;
/* Sanity check */
@@ -1148,15 +1152,8 @@ static int x509_check_signature ( struct x509_certificate *cert,
}
/* Verify signature using signer's public key */
- if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data,
- public_key->raw.len ) ) != 0 ) {
- DBGC ( cert, "X509 %p \"%s\" cannot initialise public key: "
- "%s\n", cert, x509_name ( cert ), strerror ( rc ) );
- goto err_pubkey_init;
- }
- if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out,
- signature->value.data,
- signature->value.len ) ) != 0 ) {
+ if ( ( rc = pubkey_verify ( pubkey, &public_key->raw, digest,
+ digest_out, &signature->value ) ) != 0 ) {
DBGC ( cert, "X509 %p \"%s\" signature verification failed: "
"%s\n", cert, x509_name ( cert ), strerror ( rc ) );
goto err_pubkey_verify;
@@ -1166,8 +1163,6 @@ static int x509_check_signature ( struct x509_certificate *cert,
rc = 0;
err_pubkey_verify:
- pubkey_final ( pubkey, pubkey_ctx );
- err_pubkey_init:
err_mismatch:
return rc;
}
@@ -1331,9 +1326,9 @@ int x509_is_valid ( struct x509_certificate *cert, struct x509_root *root ) {
* @v issuer Issuing X.509 certificate (or NULL)
* @v root Root certificate list
*/
-static void x509_set_valid ( struct x509_certificate *cert,
- struct x509_certificate *issuer,
- struct x509_root *root ) {
+void x509_set_valid ( struct x509_certificate *cert,
+ struct x509_certificate *issuer,
+ struct x509_root *root ) {
unsigned int max_path_remaining;
/* Sanity checks */
@@ -1642,11 +1637,17 @@ struct x509_chain * x509_alloc_chain ( void ) {
*/
int x509_append ( struct x509_chain *chain, struct x509_certificate *cert ) {
struct x509_link *link;
+ int rc;
+
+ /* Ensure allocation of link cannot invalidate certificate */
+ x509_get ( cert );
/* Allocate link */
link = zalloc ( sizeof ( *link ) );
- if ( ! link )
- return -ENOMEM;
+ if ( ! link ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
/* Add link to chain */
link->cert = x509_get ( cert );
@@ -1654,7 +1655,12 @@ int x509_append ( struct x509_chain *chain, struct x509_certificate *cert ) {
DBGC ( chain, "X509 chain %p added X509 %p \"%s\"\n",
chain, cert, x509_name ( cert ) );
- return 0;
+ /* Success */
+ rc = 0;
+
+ x509_put ( cert );
+ err_alloc:
+ return rc;
}
/**
@@ -1711,25 +1717,139 @@ void x509_truncate ( struct x509_chain *chain, struct x509_link *link ) {
}
/**
+ * Mark X.509 certificate as found
+ *
+ * @v store Certificate store
+ * @v cert X.509 certificate
+ * @ret cert X.509 certificate
+ */
+static struct x509_certificate * x509_found ( struct x509_chain *store,
+ struct x509_certificate *cert ) {
+
+ /* Sanity check */
+ assert ( store != NULL );
+
+ /* Mark as found, if applicable */
+ if ( store->found )
+ store->found ( store, cert );
+
+ return cert;
+}
+
+/**
+ * Identify X.509 certificate by raw certificate data
+ *
+ * @v store Certificate store, or NULL to use default
+ * @v raw Raw certificate data
+ * @ret cert X.509 certificate, or NULL if not found
+ */
+struct x509_certificate * x509_find ( struct x509_chain *store,
+ const struct asn1_cursor *raw ) {
+ struct x509_link *link;
+ struct x509_certificate *cert;
+
+ /* Use default certificate store if none specified */
+ if ( ! store )
+ store = &certstore;
+
+ /* Search for certificate within store */
+ list_for_each_entry ( link, &store->links, list ) {
+
+ /* Check raw certificate data */
+ cert = link->cert;
+ if ( asn1_compare ( raw, &cert->raw ) == 0 )
+ return x509_found ( store, cert );
+ }
+
+ return NULL;
+}
+
+/**
* Identify X.509 certificate by subject
*
- * @v certs X.509 certificate list
+ * @v store Certificate store, or NULL to use default
* @v subject Subject
* @ret cert X.509 certificate, or NULL if not found
*/
-static struct x509_certificate *
-x509_find_subject ( struct x509_chain *certs,
+struct x509_certificate *
+x509_find_subject ( struct x509_chain *store,
const struct asn1_cursor *subject ) {
struct x509_link *link;
struct x509_certificate *cert;
+ /* Use default certificate store if none specified */
+ if ( ! store )
+ store = &certstore;
+
/* Scan through certificate list */
- list_for_each_entry ( link, &certs->links, list ) {
+ list_for_each_entry ( link, &store->links, list ) {
/* Check subject */
cert = link->cert;
if ( asn1_compare ( subject, &cert->subject.raw ) == 0 )
- return cert;
+ return x509_found ( store, cert );
+ }
+
+ return NULL;
+}
+
+/**
+ * Identify X.509 certificate by issuer and serial number
+ *
+ * @v store Certificate store, or NULL to use default
+ * @v issuer Issuer
+ * @v serial Serial number
+ * @ret cert X.509 certificate, or NULL if not found
+ */
+struct x509_certificate *
+x509_find_issuer_serial ( struct x509_chain *store,
+ const struct asn1_cursor *issuer,
+ const struct asn1_cursor *serial ) {
+ struct x509_link *link;
+ struct x509_certificate *cert;
+
+ /* Use default certificate store if none specified */
+ if ( ! store )
+ store = &certstore;
+
+ /* Scan through certificate list */
+ list_for_each_entry ( link, &store->links, list ) {
+
+ /* Check issuer and serial number */
+ cert = link->cert;
+ if ( ( asn1_compare ( issuer, &cert->issuer.raw ) == 0 ) &&
+ ( asn1_compare ( serial, &cert->serial.raw ) == 0 ) )
+ return x509_found ( store, cert );
+ }
+
+ return NULL;
+}
+
+/**
+ * Identify X.509 certificate by corresponding public key
+ *
+ * @v store Certificate store, or NULL to use default
+ * @v key Private key
+ * @ret cert X.509 certificate, or NULL if not found
+ */
+struct x509_certificate * x509_find_key ( struct x509_chain *store,
+ struct private_key *key ) {
+ struct x509_link *link;
+ struct x509_certificate *cert;
+
+ /* Use default certificate store if none specified */
+ if ( ! store )
+ store = &certstore;
+
+ /* Scan through certificate list */
+ list_for_each_entry ( link, &store->links, list ) {
+
+ /* Check public key */
+ cert = link->cert;
+ if ( pubkey_match ( cert->signature_algorithm->pubkey,
+ privkey_cursor ( key ),
+ &cert->subject.public_key.raw ) == 0 )
+ return x509_found ( store, cert );
}
return NULL;
@@ -1739,13 +1859,13 @@ x509_find_subject ( struct x509_chain *certs,
* Append X.509 certificates to X.509 certificate chain
*
* @v chain X.509 certificate chain
- * @v certs X.509 certificate list
+ * @v store Certificate store, or NULL to use default
* @ret rc Return status code
*
* Certificates will be automatically appended to the chain based upon
* the subject and issuer names.
*/
-int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ) {
+int x509_auto_append ( struct x509_chain *chain, struct x509_chain *store ) {
struct x509_certificate *cert;
struct x509_certificate *previous;
int rc;
@@ -1762,7 +1882,7 @@ int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ) {
/* Find issuing certificate */
previous = cert;
- cert = x509_find_subject ( certs, &cert->issuer.raw );
+ cert = x509_find_subject ( store, &cert->issuer.raw );
if ( ! cert )
break;
if ( cert == previous )
@@ -1791,10 +1911,6 @@ int x509_validate_chain ( struct x509_chain *chain, time_t time,
struct x509_link *link;
int rc;
- /* Use default certificate store if none specified */
- if ( ! store )
- store = &certstore;
-
/* Append any applicable certificates from the certificate store */
if ( ( rc = x509_auto_append ( chain, store ) ) != 0 )
return rc;