/* * 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 <stdlib.h> #include <string.h> #include <errno.h> #include <gpxe/asn1.h> #include <gpxe/x509.h> /** @file * * X.509 certificates * * The structure of X.509v3 certificates is concisely documented in * RFC5280 section 4.1. The structure of RSA public keys is * documented in RFC2313. */ /** Object Identifier for "rsaEncryption" (1.2.840.113549.1.1.1) */ static const uint8_t oid_rsa_encryption[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 }; /** * Identify X.509 certificate public key * * @v certificate Certificate * @v algorithm Public key algorithm to fill in * @v pubkey Public key value to fill in * @ret rc Return status code */ static int x509_public_key ( const struct asn1_cursor *certificate, struct asn1_cursor *algorithm, struct asn1_cursor *pubkey ) { struct asn1_cursor cursor; int rc; /* Locate subjectPublicKeyInfo */ memcpy ( &cursor, certificate, sizeof ( cursor ) ); rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */ asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */ asn1_skip ( &cursor, ASN1_EXPLICIT_TAG ), /* version */ asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */ asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */ asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */ asn1_skip ( &cursor, ASN1_SEQUENCE ), /* validity */ asn1_skip ( &cursor, ASN1_SEQUENCE ), /* name */ asn1_enter ( &cursor, ASN1_SEQUENCE )/* subjectPublicKeyInfo*/); if ( rc != 0 ) { DBG ( "Cannot locate subjectPublicKeyInfo in:\n" ); DBG_HDA ( 0, certificate->data, certificate->len ); return rc; } /* Locate algorithm */ memcpy ( algorithm, &cursor, sizeof ( *algorithm ) ); rc = ( asn1_enter ( algorithm, ASN1_SEQUENCE ) /* algorithm */ ); if ( rc != 0 ) { DBG ( "Cannot locate algorithm in:\n" ); DBG_HDA ( 0, certificate->data, certificate->len ); return rc; } /* Locate subjectPublicKey */ memcpy ( pubkey, &cursor, sizeof ( *pubkey ) ); rc = ( asn1_skip ( pubkey, ASN1_SEQUENCE ), /* algorithm */ asn1_enter ( pubkey, ASN1_BIT_STRING ) /* subjectPublicKey*/ ); if ( rc != 0 ) { DBG ( "Cannot locate subjectPublicKey in:\n" ); DBG_HDA ( 0, certificate->data, certificate->len ); return rc; } return 0; } /** * Identify X.509 certificate RSA modulus and public exponent * * @v certificate Certificate * @v rsa RSA public key to fill in * @ret rc Return status code * * The caller is responsible for eventually calling * x509_free_rsa_public_key() to free the storage allocated to hold * the RSA modulus and exponent. */ int x509_rsa_public_key ( const struct asn1_cursor *certificate, struct x509_rsa_public_key *rsa_pubkey ) { struct asn1_cursor algorithm; struct asn1_cursor pubkey; struct asn1_cursor modulus; struct asn1_cursor exponent; int rc; /* First, extract the public key algorithm and key data */ if ( ( rc = x509_public_key ( certificate, &algorithm, &pubkey ) ) != 0 ) return rc; /* Check that algorithm is RSA */ rc = ( asn1_enter ( &algorithm, ASN1_OID ) /* algorithm */ ); if ( rc != 0 ) { DBG ( "Cannot locate algorithm:\n" ); DBG_HDA ( 0, certificate->data, certificate->len ); return rc; } if ( ( algorithm.len != sizeof ( oid_rsa_encryption ) ) || ( memcmp ( algorithm.data, &oid_rsa_encryption, sizeof ( oid_rsa_encryption ) ) != 0 ) ) { DBG ( "algorithm is not rsaEncryption in:\n" ); DBG_HDA ( 0, certificate->data, certificate->len ); return -ENOTSUP; } /* Check that public key is a byte string, i.e. that the * "unused bits" byte contains zero. */ if ( ( pubkey.len < 1 ) || ( ( *( uint8_t * ) pubkey.data ) != 0 ) ) { DBG ( "subjectPublicKey is not a byte string in:\n" ); DBG_HDA ( 0, certificate->data, certificate->len ); return -ENOTSUP; } pubkey.data++; pubkey.len--; /* Pick out the modulus and exponent */ rc = ( asn1_enter ( &pubkey, ASN1_SEQUENCE ) /* RSAPublicKey */ ); if ( rc != 0 ) { DBG ( "Cannot locate RSAPublicKey in:\n" ); DBG_HDA ( 0, certificate->data, certificate->len ); return -ENOTSUP; } memcpy ( &modulus, &pubkey, sizeof ( modulus ) ); rc = ( asn1_enter ( &modulus, ASN1_INTEGER ) /* modulus */ ); if ( rc != 0 ) { DBG ( "Cannot locate modulus in:\n" ); DBG_HDA ( 0, certificate->data, certificate->len ); return -ENOTSUP; } memcpy ( &exponent, &pubkey, sizeof ( exponent ) ); rc = ( asn1_skip ( &exponent, ASN1_INTEGER ), /* modulus */ asn1_enter ( &exponent, ASN1_INTEGER ) /* publicExponent */ ); if ( rc != 0 ) { DBG ( "Cannot locate publicExponent in:\n" ); DBG_HDA ( 0, certificate->data, certificate->len ); return -ENOTSUP; } /* Allocate space and copy out modulus and exponent */ rsa_pubkey->modulus = malloc ( modulus.len + exponent.len ); if ( ! rsa_pubkey->modulus ) return -ENOMEM; rsa_pubkey->exponent = ( rsa_pubkey->modulus + modulus.len ); memcpy ( rsa_pubkey->modulus, modulus.data, modulus.len ); rsa_pubkey->modulus_len = modulus.len; memcpy ( rsa_pubkey->exponent, exponent.data, exponent.len ); rsa_pubkey->exponent_len = exponent.len; DBG2 ( "RSA modulus:\n" ); DBG2_HDA ( 0, rsa_pubkey->modulus, rsa_pubkey->modulus_len ); DBG2 ( "RSA exponent:\n" ); DBG2_HDA ( 0, rsa_pubkey->exponent, rsa_pubkey->exponent_len ); return 0; }