From 38b7e43f7d88a35b23b2d44a72d07d2ee589d31e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Mar 2012 13:57:32 +0000 Subject: [PATCH] [crypto] Generalise X.509 OID-identified algorithm to asn1.c The concept of an OID-identified algorithm as defined in X.509 is used in some other standards (e.g. PKCS#7). Generalise this functionality and provide it as part of the ASN.1 core. Signed-off-by: Michael Brown --- src/crypto/asn1.c | 54 ++++++++++++++++++ src/crypto/rsa.c | 47 +++++++++++++++ src/crypto/x509.c | 123 +++++++++------------------------------- src/include/ipxe/asn1.h | 23 ++++++++ src/include/ipxe/x509.h | 29 +--------- 5 files changed, 155 insertions(+), 121 deletions(-) diff --git a/src/crypto/asn1.c b/src/crypto/asn1.c index f075b66d..cd502502 100644 --- a/src/crypto/asn1.c +++ b/src/crypto/asn1.c @@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** @file @@ -341,3 +342,56 @@ int asn1_compare ( const struct asn1_cursor *cursor1, return ( difference ? difference : memcmp ( cursor1->data, cursor2->data, cursor1->len ) ); } + +/** + * Identify ASN.1 algorithm by OID + * + * @v cursor ASN.1 object cursor + + * @ret algorithm Algorithm, or NULL + */ +static struct asn1_algorithm * +asn1_find_algorithm ( const struct asn1_cursor *cursor ) { + struct asn1_algorithm *algorithm; + + for_each_table_entry ( algorithm, ASN1_ALGORITHMS ) { + if ( asn1_compare ( &algorithm->oid, cursor ) == 0 ) + return algorithm; + } + + return NULL; +} + +/** + * Parse ASN.1 OID-identified algorithm + * + * @v cursor ASN.1 object cursor + * @ret algorithm Algorithm, or NULL + */ +struct asn1_algorithm * asn1_algorithm ( const struct asn1_cursor *cursor ) { + struct asn1_cursor contents; + struct asn1_algorithm *algorithm; + int rc; + + /* Enter signatureAlgorithm */ + memcpy ( &contents, cursor, sizeof ( contents ) ); + asn1_enter ( &contents, ASN1_SEQUENCE ); + + /* Enter algorithm */ + if ( ( rc = asn1_enter ( &contents, ASN1_OID ) ) != 0 ) { + DBGC ( cursor, "ASN1 %p cannot locate algorithm OID:\n", + cursor ); + DBGC_HDA ( cursor, 0, cursor->data, cursor->len ); + return NULL; + } + + /* Identify algorithm */ + algorithm = asn1_find_algorithm ( &contents ); + if ( ! algorithm ) { + DBGC ( cursor, "ASN1 %p unrecognised algorithm:\n", cursor ); + DBGC_HDA ( cursor, 0, cursor->data, cursor->len ); + return NULL; + } + + return algorithm; +} diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index 9b98b179..62f52c95 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -39,6 +39,53 @@ FILE_LICENCE ( GPL2_OR_LATER ); * RSA is documented in RFC 3447. */ +/** "rsaEncryption" object identifier */ +static uint8_t oid_rsa_encryption[] = { ASN1_OID_RSAENCRYPTION }; + +/** "md5WithRSAEncryption" object identifier */ +static uint8_t oid_md5_with_rsa_encryption[] = + { ASN1_OID_MD5WITHRSAENCRYPTION }; + +/** "sha1WithRSAEncryption" object identifier */ +static uint8_t oid_sha1_with_rsa_encryption[] = + { ASN1_OID_SHA1WITHRSAENCRYPTION }; + +/** "sha256WithRSAEncryption" object identifier */ +static uint8_t oid_sha256_with_rsa_encryption[] = + { ASN1_OID_SHA256WITHRSAENCRYPTION }; + +/** "rsaEncryption" OID-identified algorithm */ +struct asn1_algorithm rsa_encryption_algorithm __asn1_algorithm = { + .name = "rsaEncryption", + .pubkey = &rsa_algorithm, + .digest = NULL, + .oid = ASN1_OID_CURSOR ( oid_rsa_encryption ), +}; + +/** "md5WithRSAEncryption" OID-identified algorithm */ +struct asn1_algorithm md5_with_rsa_encryption_algorithm __asn1_algorithm = { + .name = "md5WithRSAEncryption", + .pubkey = &rsa_algorithm, + .digest = &md5_algorithm, + .oid = ASN1_OID_CURSOR ( oid_md5_with_rsa_encryption ), +}; + +/** "sha1WithRSAEncryption" OID-identified algorithm */ +struct asn1_algorithm sha1_with_rsa_encryption_algorithm __asn1_algorithm = { + .name = "sha1WithRSAEncryption", + .pubkey = &rsa_algorithm, + .digest = &sha1_algorithm, + .oid = ASN1_OID_CURSOR ( oid_sha1_with_rsa_encryption ), +}; + +/** "sha256WithRSAEncryption" OID-identified algorithm */ +struct asn1_algorithm sha256_with_rsa_encryption_algorithm __asn1_algorithm = { + .name = "sha256WithRSAEncryption", + .pubkey = &rsa_algorithm, + .digest = &sha256_algorithm, + .oid = ASN1_OID_CURSOR ( oid_sha256_with_rsa_encryption ), +}; + /** MD5 digestInfo prefix */ static const uint8_t rsa_md5_prefix_data[] = { RSA_DIGESTINFO_PREFIX ( MD5_DIGEST_SIZE, ASN1_OID_MD5 ) }; diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 449d07e2..5ce42f88 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -49,10 +49,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); __einfo_error ( EINFO_ENOTSUP_EXTENSION ) #define EINFO_ENOTSUP_EXTENSION \ __einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported extension" ) -#define EINVAL_NON_SIGNATURE \ - __einfo_error ( EINFO_EINVAL_NON_SIGNATURE ) -#define EINFO_EINVAL_NON_SIGNATURE \ - __einfo_uniqify ( EINFO_EINVAL, 0x01, "Not a signature algorithm" ) +#define EINVAL_ALGORITHM \ + __einfo_error ( EINFO_EINVAL_ALGORITHM ) +#define EINFO_EINVAL_ALGORITHM \ + __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid algorithm type" ) #define EINVAL_BIT_STRING \ __einfo_error ( EINFO_EINVAL_BIT_STRING ) #define EINFO_EINVAL_BIT_STRING \ @@ -101,70 +101,6 @@ static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME }; static struct asn1_cursor oid_common_name_cursor = ASN1_OID_CURSOR ( oid_common_name ); -/** "rsaEncryption" object identifier */ -static uint8_t oid_rsa_encryption[] = { ASN1_OID_RSAENCRYPTION }; - -/** "md5WithRSAEncryption" object identifier */ -static uint8_t oid_md5_with_rsa_encryption[] = - { ASN1_OID_MD5WITHRSAENCRYPTION }; - -/** "sha1WithRSAEncryption" object identifier */ -static uint8_t oid_sha1_with_rsa_encryption[] = - { ASN1_OID_SHA1WITHRSAENCRYPTION }; - -/** "sha256WithRSAEncryption" object identifier */ -static uint8_t oid_sha256_with_rsa_encryption[] = - { ASN1_OID_SHA256WITHRSAENCRYPTION }; - -/** Supported algorithms */ -static struct x509_algorithm x509_algorithms[] = { - { - .name = "rsaEncryption", - .pubkey = &rsa_algorithm, - .digest = NULL, - .oid = ASN1_OID_CURSOR ( oid_rsa_encryption ), - }, - { - .name = "md5WithRSAEncryption", - .pubkey = &rsa_algorithm, - .digest = &md5_algorithm, - .oid = ASN1_OID_CURSOR ( oid_md5_with_rsa_encryption ), - }, - { - .name = "sha1WithRSAEncryption", - .pubkey = &rsa_algorithm, - .digest = &sha1_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha1_with_rsa_encryption ), - }, - { - .name = "sha256WithRSAEncryption", - .pubkey = &rsa_algorithm, - .digest = &sha256_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha256_with_rsa_encryption ), - }, -}; - -/** - * Identify X.509 algorithm by OID - * - * @v oid OID - * @ret algorithm Algorithm, or NULL - */ -static struct x509_algorithm * -x509_find_algorithm ( const struct asn1_cursor *oid ) { - struct x509_algorithm *algorithm; - unsigned int i; - - for ( i = 0 ; i < ( sizeof ( x509_algorithms ) / - sizeof ( x509_algorithms[0] ) ) ; i++ ) { - algorithm = &x509_algorithms[i]; - if ( asn1_compare ( &algorithm->oid, oid ) == 0 ) - return algorithm; - } - - return NULL; -} - /** * Parse X.509 certificate algorithm * @@ -173,29 +109,24 @@ x509_find_algorithm ( const struct asn1_cursor *oid ) { * @v raw ASN.1 cursor * @ret rc Return status code */ -static int x509_parse_algorithm ( struct x509_certificate *cert, - struct x509_algorithm **algorithm, +int x509_parse_pubkey_algorithm ( struct x509_certificate *cert, + struct asn1_algorithm **algorithm, const struct asn1_cursor *raw ) { - struct asn1_cursor cursor; - int rc; - /* Enter signatureAlgorithm */ - memcpy ( &cursor, raw, sizeof ( cursor ) ); - asn1_enter ( &cursor, ASN1_SEQUENCE ); - - /* Enter algorithm */ - if ( ( rc = asn1_enter ( &cursor, ASN1_OID ) ) != 0 ) { - DBGC ( cert, "X509 %p cannot locate algorithm:\n", cert ); + /* Parse algorithm */ + *algorithm = asn1_algorithm ( raw ); + if ( ! (*algorithm) ) { + DBGC ( cert, "X509 %p unrecognised algorithm:\n", cert ); DBGC_HDA ( cert, 0, raw->data, raw->len ); - return rc; + return -ENOTSUP_ALGORITHM; } - /* Identify algorithm */ - *algorithm = x509_find_algorithm ( &cursor ); - if ( ! *algorithm ) { - DBGC ( cert, "X509 %p unsupported algorithm:\n", cert ); - DBGC_HDA ( cert, 0, cursor.data, cursor.len ); - return -ENOTSUP_ALGORITHM; + /* Check algorithm has a public key */ + if ( ! (*algorithm)->pubkey ) { + DBGC ( cert, "X509 %p algorithm %s is not a public-key " + "algorithm:\n", cert, (*algorithm)->name ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -EINVAL_ALGORITHM; } return 0; @@ -210,20 +141,21 @@ static int x509_parse_algorithm ( struct x509_certificate *cert, * @ret rc Return status code */ static int x509_parse_signature_algorithm ( struct x509_certificate *cert, - struct x509_algorithm **algorithm, + struct asn1_algorithm **algorithm, const struct asn1_cursor *raw ) { int rc; /* Parse algorithm */ - if ( ( rc = x509_parse_algorithm ( cert, algorithm, raw ) ) != 0 ) + if ( ( rc = x509_parse_pubkey_algorithm ( cert, algorithm, + raw ) ) != 0 ) return rc; /* Check algorithm is a signature algorithm */ - if ( ! x509_is_signature_algorithm ( *algorithm ) ) { + if ( ! (*algorithm)->digest ) { DBGC ( cert, "X509 %p algorithm %s is not a signature " "algorithm:\n", cert, (*algorithm)->name ); DBGC_HDA ( cert, 0, raw->data, raw->len ); - return -EINVAL_NON_SIGNATURE; + return -EINVAL_ALGORITHM; } return 0; @@ -600,7 +532,7 @@ static int x509_parse_subject ( struct x509_certificate *cert, 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 x509_algorithm **algorithm = &public_key->algorithm; + struct asn1_algorithm **algorithm = &public_key->algorithm; struct asn1_cursor cursor; int rc; @@ -613,7 +545,8 @@ static int x509_parse_public_key ( struct x509_certificate *cert, asn1_enter ( &cursor, ASN1_SEQUENCE ); /* Parse algorithm */ - if ( ( rc = x509_parse_algorithm ( cert, algorithm, &cursor ) ) != 0 ) + if ( ( rc = x509_parse_pubkey_algorithm ( cert, algorithm, + &cursor ) ) != 0 ) return rc; DBGC ( cert, "X509 %p public key algorithm is %s\n", cert, (*algorithm)->name ); @@ -866,7 +799,7 @@ static int x509_parse_extensions ( struct x509_certificate *cert, */ static int x509_parse_tbscertificate ( struct x509_certificate *cert, const struct asn1_cursor *raw ) { - struct x509_algorithm **algorithm = &cert->signature_algorithm; + struct asn1_algorithm **algorithm = &cert->signature_algorithm; struct asn1_cursor cursor; int rc; @@ -933,7 +866,7 @@ static int x509_parse_tbscertificate ( struct x509_certificate *cert, */ int x509_parse ( struct x509_certificate *cert, const void *data, size_t len ) { struct x509_signature *signature = &cert->signature; - struct x509_algorithm **signature_algorithm = &signature->algorithm; + struct asn1_algorithm **signature_algorithm = &signature->algorithm; struct x509_bit_string *signature_value = &signature->value; struct asn1_cursor cursor; int rc; @@ -991,7 +924,7 @@ int x509_parse ( struct x509_certificate *cert, const void *data, size_t len ) { static int x509_check_signature ( struct x509_certificate *cert, struct x509_public_key *public_key ) { struct x509_signature *signature = &cert->signature; - struct x509_algorithm *algorithm = signature->algorithm; + struct asn1_algorithm *algorithm = signature->algorithm; struct digest_algorithm *digest = algorithm->digest; struct pubkey_algorithm *pubkey = algorithm->pubkey; uint8_t digest_ctx[ digest->ctxsize ]; diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index f912f5f5..553a8f3c 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -9,6 +9,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include +#include + /** An ASN.1 object cursor */ struct asn1_cursor { /** Start of data */ @@ -143,6 +146,24 @@ struct asn1_cursor { .len = sizeof ( oid_value ), \ } +/** An ASN.1 OID-identified algorithm */ +struct asn1_algorithm { + /** Name */ + const char *name; + /** Object identifier */ + struct asn1_cursor oid; + /** Public-key algorithm (if applicable) */ + struct pubkey_algorithm *pubkey; + /** Digest algorithm (if applicable) */ + struct digest_algorithm *digest; +}; + +/** ASN.1 OID-identified algorithms */ +#define ASN1_ALGORITHMS __table ( struct asn1_algorithm, "asn1_algorithms" ) + +/** Declare an ASN.1 OID-identified algorithm */ +#define __asn1_algorithm __table_entry ( ASN1_ALGORITHMS, 01 ) + /** An ASN.1 boolean */ struct asn1_boolean { /** Value */ @@ -181,5 +202,7 @@ extern int asn1_boolean ( const struct asn1_cursor *cursor ); extern int asn1_integer ( const struct asn1_cursor *cursor, int *value ); extern int asn1_compare ( const struct asn1_cursor *cursor1, const struct asn1_cursor *cursor2 ); +extern struct asn1_algorithm * +asn1_algorithm ( const struct asn1_cursor *cursor ); #endif /* _IPXE_ASN1_H */ diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 89f90b84..45f738cd 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -14,29 +14,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include -/** 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 */ @@ -80,7 +57,7 @@ struct x509_public_key { /** Raw public key */ struct asn1_cursor raw; /** Public key algorithm */ - struct x509_algorithm *algorithm; + struct asn1_algorithm *algorithm; }; /** An X.509 certificate subject */ @@ -96,7 +73,7 @@ struct x509_subject { /** An X.509 certificate signature */ struct x509_signature { /** Signature algorithm */ - struct x509_algorithm *algorithm; + struct asn1_algorithm *algorithm; /** Signature value */ struct x509_bit_string value; }; @@ -147,7 +124,7 @@ struct x509_certificate { /** Raw tbsCertificate */ struct asn1_cursor tbs; /** Signature algorithm */ - struct x509_algorithm *signature_algorithm; + struct asn1_algorithm *signature_algorithm; /** Issuer */ struct x509_issuer issuer; /** Validity */