/** * Parse OCSP certificate ID * * @v ocsp OCSP check * @v raw ASN.1 cursor * @ret rc Return status code */ static int ocsp_parse_cert_id ( struct ocsp_check *ocsp, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; struct asn1_algorithm *algorithm; int rc; /* Check certID algorithm */ memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_SEQUENCE ); if ( ( rc = asn1_digest_algorithm ( &cursor, &algorithm ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" certID unknown algorithm: %s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } if ( algorithm->digest != &ocsp_digest_algorithm ) { DBGC ( ocsp, "OCSP %p \"%s\" certID wrong algorithm %s\n", ocsp, x509_name ( ocsp->cert ), algorithm->digest->name ); return -EACCES_CERT_MISMATCH; } /* Check remaining certID fields */ asn1_skip ( &cursor, ASN1_SEQUENCE ); if ( asn1_compare ( &cursor, &ocsp->request.cert_id_tail ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" certID mismatch:\n", ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, ocsp->request.cert_id_tail.data, ocsp->request.cert_id_tail.len ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); return -EACCES_CERT_MISMATCH; } return 0; }
/** * Build OCSP request * * @v ocsp OCSP check * @ret rc Return status code */ static int ocsp_request ( struct ocsp_check *ocsp ) { struct digest_algorithm *digest = &ocsp_digest_algorithm; struct asn1_builder *builder = &ocsp->request.builder; struct asn1_cursor *cert_id_tail = &ocsp->request.cert_id_tail; uint8_t digest_ctx[digest->ctxsize]; uint8_t name_digest[digest->digestsize]; uint8_t pubkey_digest[digest->digestsize]; int rc; /* Generate digests */ digest_init ( digest, digest_ctx ); digest_update ( digest, digest_ctx, ocsp->cert->issuer.raw.data, ocsp->cert->issuer.raw.len ); digest_final ( digest, digest_ctx, name_digest ); digest_init ( digest, digest_ctx ); digest_update ( digest, digest_ctx, ocsp->issuer->subject.public_key.raw_bits.data, ocsp->issuer->subject.public_key.raw_bits.len ); digest_final ( digest, digest_ctx, pubkey_digest ); /* Construct request */ if ( ( rc = ( asn1_prepend_raw ( builder, ocsp->cert->serial.raw.data, ocsp->cert->serial.raw.len ), asn1_prepend ( builder, ASN1_OCTET_STRING, pubkey_digest, sizeof ( pubkey_digest ) ), asn1_prepend ( builder, ASN1_OCTET_STRING, name_digest, sizeof ( name_digest ) ), asn1_prepend ( builder, ASN1_SEQUENCE, ocsp_algorithm_id, sizeof ( ocsp_algorithm_id ) ), asn1_wrap ( builder, ASN1_SEQUENCE ), asn1_wrap ( builder, ASN1_SEQUENCE ), asn1_wrap ( builder, ASN1_SEQUENCE ), asn1_wrap ( builder, ASN1_SEQUENCE ), asn1_wrap ( builder, ASN1_SEQUENCE ) ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not build request: %s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" request is:\n", ocsp, x509_name ( ocsp->cert ) ); DBGC2_HDA ( ocsp, 0, builder->data, builder->len ); /* Parse certificate ID for comparison with response */ cert_id_tail->data = builder->data; cert_id_tail->len = builder->len; if ( ( rc = ( asn1_enter ( cert_id_tail, ASN1_SEQUENCE ), asn1_enter ( cert_id_tail, ASN1_SEQUENCE ), asn1_enter ( cert_id_tail, ASN1_SEQUENCE ), asn1_enter ( cert_id_tail, ASN1_SEQUENCE ), asn1_enter ( cert_id_tail, ASN1_SEQUENCE ), asn1_skip ( cert_id_tail, ASN1_SEQUENCE ) ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not locate certID: %s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } return 0; }
/** * 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_if_exists ( &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; } if ( modulus.len && ( ! *( ( uint8_t * ) modulus.data ) ) ) { /* Skip positive sign byte */ modulus.data++; modulus.len--; } 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; } if ( exponent.len && ( ! *( ( uint8_t * ) exponent.data ) ) ) { /* Skip positive sign byte */ exponent.data++; exponent.len--; } /* 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; }