Home | History | Annotate | Download | only in crypto
      1 /*
      2  * Copyright (C) 2007 Michael Brown <mbrown (at) fensystems.co.uk>.
      3  *
      4  * This program is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU General Public License as
      6  * published by the Free Software Foundation; either version 2 of the
      7  * License, or any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful, but
     10  * WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program; if not, write to the Free Software
     16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     17  */
     18 
     19 FILE_LICENCE ( GPL2_OR_LATER );
     20 
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <errno.h>
     24 #include <gpxe/asn1.h>
     25 #include <gpxe/x509.h>
     26 
     27 /** @file
     28  *
     29  * X.509 certificates
     30  *
     31  * The structure of X.509v3 certificates is concisely documented in
     32  * RFC5280 section 4.1.  The structure of RSA public keys is
     33  * documented in RFC2313.
     34  */
     35 
     36 /** Object Identifier for "rsaEncryption" (1.2.840.113549.1.1.1) */
     37 static const uint8_t oid_rsa_encryption[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7,
     38 					      0x0d, 0x01, 0x01, 0x01 };
     39 
     40 /**
     41  * Identify X.509 certificate public key
     42  *
     43  * @v certificate	Certificate
     44  * @v algorithm		Public key algorithm to fill in
     45  * @v pubkey		Public key value to fill in
     46  * @ret rc		Return status code
     47  */
     48 static int x509_public_key ( const struct asn1_cursor *certificate,
     49 			     struct asn1_cursor *algorithm,
     50 			     struct asn1_cursor *pubkey ) {
     51 	struct asn1_cursor cursor;
     52 	int rc;
     53 
     54 	/* Locate subjectPublicKeyInfo */
     55 	memcpy ( &cursor, certificate, sizeof ( cursor ) );
     56 	rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */
     57 	       asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */
     58 	       asn1_skip ( &cursor, ASN1_EXPLICIT_TAG ), /* version */
     59 	       asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */
     60 	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */
     61 	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */
     62 	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* validity */
     63 	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* name */
     64 	       asn1_enter ( &cursor, ASN1_SEQUENCE )/* subjectPublicKeyInfo*/);
     65 	if ( rc != 0 ) {
     66 		DBG ( "Cannot locate subjectPublicKeyInfo in:\n" );
     67 		DBG_HDA ( 0, certificate->data, certificate->len );
     68 		return rc;
     69 	}
     70 
     71 	/* Locate algorithm */
     72 	memcpy ( algorithm, &cursor, sizeof ( *algorithm ) );
     73 	rc = ( asn1_enter ( algorithm, ASN1_SEQUENCE ) /* algorithm */ );
     74 	if ( rc != 0 ) {
     75 		DBG ( "Cannot locate algorithm in:\n" );
     76 		DBG_HDA ( 0, certificate->data, certificate->len );
     77 		return rc;
     78 	}
     79 
     80 	/* Locate subjectPublicKey */
     81 	memcpy ( pubkey, &cursor, sizeof ( *pubkey ) );
     82 	rc = ( asn1_skip ( pubkey, ASN1_SEQUENCE ), /* algorithm */
     83 	       asn1_enter ( pubkey, ASN1_BIT_STRING ) /* subjectPublicKey*/ );
     84 	if ( rc != 0 ) {
     85 		DBG ( "Cannot locate subjectPublicKey in:\n" );
     86 		DBG_HDA ( 0, certificate->data, certificate->len );
     87 		return rc;
     88 	}
     89 
     90 	return 0;
     91 }
     92 
     93 /**
     94  * Identify X.509 certificate RSA modulus and public exponent
     95  *
     96  * @v certificate	Certificate
     97  * @v rsa		RSA public key to fill in
     98  * @ret rc		Return status code
     99  *
    100  * The caller is responsible for eventually calling
    101  * x509_free_rsa_public_key() to free the storage allocated to hold
    102  * the RSA modulus and exponent.
    103  */
    104 int x509_rsa_public_key ( const struct asn1_cursor *certificate,
    105 			  struct x509_rsa_public_key *rsa_pubkey ) {
    106 	struct asn1_cursor algorithm;
    107 	struct asn1_cursor pubkey;
    108 	struct asn1_cursor modulus;
    109 	struct asn1_cursor exponent;
    110 	int rc;
    111 
    112 	/* First, extract the public key algorithm and key data */
    113 	if ( ( rc = x509_public_key ( certificate, &algorithm,
    114 				      &pubkey ) ) != 0 )
    115 		return rc;
    116 
    117 	/* Check that algorithm is RSA */
    118 	rc = ( asn1_enter ( &algorithm, ASN1_OID ) /* algorithm */ );
    119 	if ( rc != 0 ) {
    120 		DBG ( "Cannot locate algorithm:\n" );
    121 		DBG_HDA ( 0, certificate->data, certificate->len );
    122 	return rc;
    123 	}
    124 	if ( ( algorithm.len != sizeof ( oid_rsa_encryption ) ) ||
    125 	     ( memcmp ( algorithm.data, &oid_rsa_encryption,
    126 			sizeof ( oid_rsa_encryption ) ) != 0 ) ) {
    127 		DBG ( "algorithm is not rsaEncryption in:\n" );
    128 		DBG_HDA ( 0, certificate->data, certificate->len );
    129 		return -ENOTSUP;
    130 	}
    131 
    132 	/* Check that public key is a byte string, i.e. that the
    133 	 * "unused bits" byte contains zero.
    134 	 */
    135 	if ( ( pubkey.len < 1 ) ||
    136 	     ( ( *( uint8_t * ) pubkey.data ) != 0 ) ) {
    137 		DBG ( "subjectPublicKey is not a byte string in:\n" );
    138 		DBG_HDA ( 0, certificate->data, certificate->len );
    139 		return -ENOTSUP;
    140 	}
    141 	pubkey.data++;
    142 	pubkey.len--;
    143 
    144 	/* Pick out the modulus and exponent */
    145 	rc = ( asn1_enter ( &pubkey, ASN1_SEQUENCE ) /* RSAPublicKey */ );
    146 	if ( rc != 0 ) {
    147 		DBG ( "Cannot locate RSAPublicKey in:\n" );
    148 		DBG_HDA ( 0, certificate->data, certificate->len );
    149 		return -ENOTSUP;
    150 	}
    151 	memcpy ( &modulus, &pubkey, sizeof ( modulus ) );
    152 	rc = ( asn1_enter ( &modulus, ASN1_INTEGER ) /* modulus */ );
    153 	if ( rc != 0 ) {
    154 		DBG ( "Cannot locate modulus in:\n" );
    155 		DBG_HDA ( 0, certificate->data, certificate->len );
    156 		return -ENOTSUP;
    157 	}
    158 	memcpy ( &exponent, &pubkey, sizeof ( exponent ) );
    159 	rc = ( asn1_skip ( &exponent, ASN1_INTEGER ), /* modulus */
    160 	       asn1_enter ( &exponent, ASN1_INTEGER ) /* publicExponent */ );
    161 	if ( rc != 0 ) {
    162 		DBG ( "Cannot locate publicExponent in:\n" );
    163 		DBG_HDA ( 0, certificate->data, certificate->len );
    164 		return -ENOTSUP;
    165 	}
    166 
    167 	/* Allocate space and copy out modulus and exponent */
    168 	rsa_pubkey->modulus = malloc ( modulus.len + exponent.len );
    169 	if ( ! rsa_pubkey->modulus )
    170 		return -ENOMEM;
    171 	rsa_pubkey->exponent = ( rsa_pubkey->modulus + modulus.len );
    172 	memcpy ( rsa_pubkey->modulus, modulus.data, modulus.len );
    173 	rsa_pubkey->modulus_len = modulus.len;
    174 	memcpy ( rsa_pubkey->exponent, exponent.data, exponent.len );
    175 	rsa_pubkey->exponent_len = exponent.len;
    176 
    177 	DBG2 ( "RSA modulus:\n" );
    178 	DBG2_HDA ( 0, rsa_pubkey->modulus, rsa_pubkey->modulus_len );
    179 	DBG2 ( "RSA exponent:\n" );
    180 	DBG2_HDA ( 0, rsa_pubkey->exponent, rsa_pubkey->exponent_len );
    181 
    182 	return 0;
    183 }
    184