/* * Parse a public key */ int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, const unsigned char *key, size_t keylen ) { int ret; unsigned char *p; #if defined(MBEDTLS_PEM_PARSE_C) size_t len; mbedtls_pem_context pem; mbedtls_pem_init( &pem ); /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ if( keylen == 0 || key[keylen - 1] != '\0' ) ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; else ret = mbedtls_pem_read_buffer( &pem, "-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----", key, NULL, 0, &len ); if( ret == 0 ) { /* * Was PEM encoded */ key = pem.buf; keylen = pem.buflen; } else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { mbedtls_pem_free( &pem ); return( ret ); } #endif /* MBEDTLS_PEM_PARSE_C */ p = (unsigned char *) key; ret = mbedtls_pk_parse_subpubkey( &p, p + keylen, ctx ); #if defined(MBEDTLS_PEM_PARSE_C) mbedtls_pem_free( &pem ); #endif return( ret ); }
/* * Parse a CSR in DER format */ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, const unsigned char *buf, size_t buflen ) { int ret; size_t len; unsigned char *p, *end; mbedtls_x509_buf sig_params; memset( &sig_params, 0, sizeof( mbedtls_x509_buf ) ); /* * Check for valid input */ if( csr == NULL || buf == NULL ) return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); mbedtls_x509_csr_init( csr ); /* * first copy the raw DER data */ p = mbedtls_calloc( 1, len = buflen ); if( p == NULL ) return( MBEDTLS_ERR_X509_ALLOC_FAILED ); memcpy( p, buf, buflen ); csr->raw.p = p; csr->raw.len = len; end = p + len; /* * CertificationRequest ::= SEQUENCE { * certificationRequestInfo CertificationRequestInfo, * signatureAlgorithm AlgorithmIdentifier, * signature BIT STRING * } */ if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_INVALID_FORMAT ); } if( len != (size_t) ( end - p ) ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); } /* * CertificationRequestInfo ::= SEQUENCE { */ csr->cri.p = p; if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); } end = p + len; csr->cri.len = end - csr->cri.p; /* * Version ::= INTEGER { v1(0) } */ if( ( ret = x509_csr_get_version( &p, end, &csr->version ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( ret ); } csr->version++; if( csr->version != 1 ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); } /* * subject Name */ csr->subject_raw.p = p; if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); } if( ( ret = mbedtls_x509_get_name( &p, p + len, &csr->subject ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( ret ); } csr->subject_raw.len = p - csr->subject_raw.p; /* * subjectPKInfo SubjectPublicKeyInfo */ if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &csr->pk ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( ret ); } /* * attributes [0] Attributes */ if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); } // TODO Parse Attributes / extension requests p += len; end = csr->raw.p + csr->raw.len; /* * signatureAlgorithm AlgorithmIdentifier, * signature BIT STRING */ if( ( ret = mbedtls_x509_get_alg( &p, end, &csr->sig_oid, &sig_params ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( ret ); } if( ( ret = mbedtls_x509_get_sig_alg( &csr->sig_oid, &sig_params, &csr->sig_md, &csr->sig_pk, &csr->sig_opts ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG ); } if( ( ret = mbedtls_x509_get_sig( &p, end, &csr->sig ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( ret ); } if( p != end ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); } return( 0 ); }
/* * Parse a CSR in DER format */ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, const unsigned char *buf, size_t buflen ) { int ret; size_t len; unsigned char *p, *end; mbedtls_x509_buf sig_params; memset( &sig_params, 0, sizeof( mbedtls_x509_buf ) ); /* * Check for valid input */ if( csr == NULL || buf == NULL ) return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); mbedtls_x509_csr_init( csr ); /* * first copy the raw DER data */ p = mbedtls_calloc( 1, len = buflen ); if( p == NULL ) return( MBEDTLS_ERR_X509_ALLOC_FAILED ); memcpy( p, buf, buflen ); csr->raw.p = p; csr->raw.len = len; end = p + len; /* * CertificationRequest ::= SEQUENCE { * certificationRequestInfo CertificationRequestInfo, * signatureAlgorithm AlgorithmIdentifier, * signature BIT STRING * } */ if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_INVALID_FORMAT ); } if( len != (size_t) ( end - p ) ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); } /* * CertificationRequestInfo ::= SEQUENCE { */ csr->cri.p = p; if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); } end = p + len; csr->cri.len = end - csr->cri.p; /* * Version ::= INTEGER { v1(0) } */ if( ( ret = x509_csr_get_version( &p, end, &csr->version ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( ret ); } csr->version++; if( csr->version != 1 ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); } /* * subject Name */ csr->subject_raw.p = p; if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); } if( ( ret = mbedtls_x509_get_name( &p, p + len, &csr->subject ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( ret ); } csr->subject_raw.len = p - csr->subject_raw.p; /* * subjectPKInfo SubjectPublicKeyInfo */ if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &csr->pk ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( ret ); } /* * attributes [0] Attributes * * The list of possible attributes is open-ended, though RFC 2985 * (PKCS#9) defines a few in section 5.4. We currently don't support any, * so we just ignore them. This is a safe thing to do as the worst thing * that could happen is that we issue a certificate that does not match * the requester's expectations - this cannot cause a violation of our * signature policies. */ if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); } p += len; end = csr->raw.p + csr->raw.len; /* * signatureAlgorithm AlgorithmIdentifier, * signature BIT STRING */ if( ( ret = mbedtls_x509_get_alg( &p, end, &csr->sig_oid, &sig_params ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( ret ); } if( ( ret = mbedtls_x509_get_sig_alg( &csr->sig_oid, &sig_params, &csr->sig_md, &csr->sig_pk, &csr->sig_opts ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG ); } if( ( ret = mbedtls_x509_get_sig( &p, end, &csr->sig ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( ret ); } if( p != end ) { mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); } return( 0 ); }
/* * Verify a signature. * * Parameters are passed using the DER encoding format following the ASN.1 * structures detailed above. */ static int verify_signature(void *data_ptr, unsigned int data_len, void *sig_ptr, unsigned int sig_len, void *sig_alg, unsigned int sig_alg_len, void *pk_ptr, unsigned int pk_len) { mbedtls_asn1_buf sig_oid, sig_params; mbedtls_asn1_buf signature; mbedtls_md_type_t md_alg; mbedtls_pk_type_t pk_alg; mbedtls_pk_context pk; int rc; void *sig_opts = NULL; const mbedtls_md_info_t *md_info; unsigned char *p, *end; unsigned char hash[MBEDTLS_MD_MAX_SIZE]; /* Get pointers to signature OID and parameters */ p = (unsigned char *)sig_alg; end = (unsigned char *)(p + sig_alg_len); rc = mbedtls_asn1_get_alg(&p, end, &sig_oid, &sig_params); if (rc != 0) { return CRYPTO_ERR_SIGNATURE; } /* Get the actual signature algorithm (MD + PK) */ rc = mbedtls_oid_get_sig_alg(&sig_oid, &md_alg, &pk_alg); if (rc != 0) { return CRYPTO_ERR_SIGNATURE; } /* Parse the public key */ mbedtls_pk_init(&pk); p = (unsigned char *)pk_ptr; end = (unsigned char *)(p + pk_len); rc = mbedtls_pk_parse_subpubkey(&p, end, &pk); if (rc != 0) { return CRYPTO_ERR_SIGNATURE; } /* Get the signature (bitstring) */ p = (unsigned char *)sig_ptr; end = (unsigned char *)(p + sig_len); signature.tag = *p; rc = mbedtls_asn1_get_bitstring_null(&p, end, &signature.len); if (rc != 0) { rc = CRYPTO_ERR_SIGNATURE; goto end; } signature.p = p; /* Calculate the hash of the data */ md_info = mbedtls_md_info_from_type(md_alg); if (md_info == NULL) { rc = CRYPTO_ERR_SIGNATURE; goto end; } p = (unsigned char *)data_ptr; rc = mbedtls_md(md_info, p, data_len, hash); if (rc != 0) { rc = CRYPTO_ERR_SIGNATURE; goto end; } /* Verify the signature */ rc = mbedtls_pk_verify_ext(pk_alg, sig_opts, &pk, md_alg, hash, mbedtls_md_get_size(md_info), signature.p, signature.len); if (rc != 0) { rc = CRYPTO_ERR_SIGNATURE; goto end; } /* Signature verification success */ rc = CRYPTO_SUCCESS; end: mbedtls_pk_free(&pk); return rc; }