/* * Parse one or more CRLs and add them to the chained list */ int x509_crl_parse( x509_crl *chain, const unsigned char *buf, size_t buflen ) { #if defined(POLARSSL_PEM_PARSE_C) int ret; size_t use_len; pem_context pem; int is_pem = 0; if( chain == NULL || buf == NULL ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); do { pem_init( &pem ); ret = pem_read_buffer( &pem, "-----BEGIN X509 CRL-----", "-----END X509 CRL-----", buf, NULL, 0, &use_len ); if( ret == 0 ) { /* * Was PEM encoded */ is_pem = 1; buflen -= use_len; buf += use_len; if( ( ret = x509_crl_parse_der( chain, pem.buf, pem.buflen ) ) != 0 ) { return( ret ); } pem_free( &pem ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { pem_free( &pem ); return( ret ); } } while( is_pem && buflen > 0 ); if( is_pem ) return( 0 ); else #endif /* POLARSSL_PEM_PARSE_C */ return( x509_crl_parse_der( chain, buf, buflen ) ); }
/* * Parse a CSR, allowing for PEM or raw DER encoding */ int x509_csr_parse( x509_csr *csr, const unsigned char *buf, size_t buflen ) { #if defined(POLARSSL_PEM_PARSE_C) int ret; size_t use_len; pem_context pem; #endif /* * Check for valid input */ if( csr == NULL || buf == NULL ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); #if defined(POLARSSL_PEM_PARSE_C) pem_init( &pem ); ret = pem_read_buffer( &pem, "-----BEGIN CERTIFICATE REQUEST-----", "-----END CERTIFICATE REQUEST-----", buf, NULL, 0, &use_len ); if( ret == 0 ) { /* * Was PEM encoded, parse the result */ if( ( ret = x509_csr_parse_der( csr, pem.buf, pem.buflen ) ) != 0 ) return( ret ); pem_free( &pem ); return( 0 ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { pem_free( &pem ); return( ret ); } else #endif /* POLARSSL_PEM_PARSE_C */ return( x509_csr_parse_der( csr, buf, buflen ) ); }
/* * Parse a public key */ int pk_parse_public_key( pk_context *ctx, const unsigned char *key, size_t keylen ) { int ret; unsigned char *p; #if defined(POLARSSL_PEM_PARSE_C) size_t len; pem_context pem; pem_init( &pem ); ret = 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 != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { pem_free( &pem ); return( ret ); } #endif /* POLARSSL_PEM_PARSE_C */ p = (unsigned char *) key; ret = pk_parse_subpubkey( &p, p + keylen, ctx ); #if defined(POLARSSL_PEM_PARSE_C) pem_free( &pem ); #endif return( ret ); }
/* * Parse a CSR */ int x509_csr_parse( x509_csr *csr, const unsigned char *buf, size_t buflen ) { int ret; size_t len; unsigned char *p, *end; #if defined(POLARSSL_PEM_PARSE_C) size_t use_len; pem_context pem; #endif /* * Check for valid input */ if( csr == NULL || buf == NULL ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); x509_csr_init( csr ); #if defined(POLARSSL_PEM_PARSE_C) pem_init( &pem ); ret = pem_read_buffer( &pem, "-----BEGIN CERTIFICATE REQUEST-----", "-----END CERTIFICATE REQUEST-----", buf, NULL, 0, &use_len ); if( ret == 0 ) { /* * Was PEM encoded */ buflen -= use_len; buf += use_len; /* * Steal PEM buffer */ p = pem.buf; pem.buf = NULL; len = pem.buflen; pem_free( &pem ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { pem_free( &pem ); return( ret ); } else #endif { /* * nope, copy the raw DER data */ p = (unsigned char *) polarssl_malloc( len = buflen ); if( p == NULL ) return( POLARSSL_ERR_X509_MALLOC_FAILED ); memcpy( p, buf, buflen ); buflen = 0; } csr->raw.p = p; csr->raw.len = len; end = p + len; /* * CertificationRequest ::= SEQUENCE { * certificationRequestInfo CertificationRequestInfo, * signatureAlgorithm AlgorithmIdentifier, * signature BIT STRING * } */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_INVALID_FORMAT ); } if( len != (size_t) ( end - p ) ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } /* * CertificationRequestInfo ::= SEQUENCE { */ csr->cri.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_csr_free( csr ); return( POLARSSL_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 ) { x509_csr_free( csr ); return( ret ); } csr->version++; if( csr->version != 1 ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_UNKNOWN_VERSION ); } /* * subject Name */ csr->subject_raw.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_INVALID_FORMAT + ret ); } if( ( ret = x509_get_name( &p, p + len, &csr->subject ) ) != 0 ) { x509_csr_free( csr ); return( ret ); } csr->subject_raw.len = p - csr->subject_raw.p; /* * subjectPKInfo SubjectPublicKeyInfo */ if( ( ret = pk_parse_subpubkey( &p, end, &csr->pk ) ) != 0 ) { x509_csr_free( csr ); return( ret ); } /* * attributes [0] Attributes */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_CONTEXT_SPECIFIC ) ) != 0 ) { x509_csr_free( csr ); return( POLARSSL_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 = x509_get_alg_null( &p, end, &csr->sig_oid ) ) != 0 ) { x509_csr_free( csr ); return( ret ); } if( ( ret = x509_get_sig_alg( &csr->sig_oid, &csr->sig_md, &csr->sig_pk ) ) != 0 ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_UNKNOWN_SIG_ALG ); } if( ( ret = x509_get_sig( &p, end, &csr->sig ) ) != 0 ) { x509_csr_free( csr ); return( ret ); } if( p != end ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } return( 0 ); }
/* * Parse a private key */ int pk_parse_key( pk_context *pk, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen ) { int ret; const pk_info_t *pk_info; #if defined(POLARSSL_PEM_PARSE_C) size_t len; pem_context pem; pem_init( &pem ); #if defined(POLARSSL_RSA_C) ret = pem_read_buffer( &pem, "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----", key, pwd, pwdlen, &len ); if( ret == 0 ) { if( ( pk_info = pk_info_from_type( POLARSSL_PK_RSA ) ) == NULL ) return( POLARSSL_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = pk_init_ctx( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_pkcs1_der( pk_rsa( *pk ), pem.buf, pem.buflen ) ) != 0 ) { pk_free( pk ); } pem_free( &pem ); return( ret ); } else if( ret == POLARSSL_ERR_PEM_PASSWORD_MISMATCH ) return( POLARSSL_ERR_PK_PASSWORD_MISMATCH ); else if( ret == POLARSSL_ERR_PEM_PASSWORD_REQUIRED ) return( POLARSSL_ERR_PK_PASSWORD_REQUIRED ); else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #endif /* POLARSSL_RSA_C */ #if defined(POLARSSL_ECP_C) ret = pem_read_buffer( &pem, "-----BEGIN EC PRIVATE KEY-----", "-----END EC PRIVATE KEY-----", key, pwd, pwdlen, &len ); if( ret == 0 ) { if( ( pk_info = pk_info_from_type( POLARSSL_PK_ECKEY ) ) == NULL ) return( POLARSSL_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = pk_init_ctx( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_sec1_der( pk_ec( *pk ), pem.buf, pem.buflen ) ) != 0 ) { pk_free( pk ); } pem_free( &pem ); return( ret ); } else if( ret == POLARSSL_ERR_PEM_PASSWORD_MISMATCH ) return( POLARSSL_ERR_PK_PASSWORD_MISMATCH ); else if( ret == POLARSSL_ERR_PEM_PASSWORD_REQUIRED ) return( POLARSSL_ERR_PK_PASSWORD_REQUIRED ); else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #endif /* POLARSSL_ECP_C */ ret = pem_read_buffer( &pem, "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----", key, NULL, 0, &len ); if( ret == 0 ) { if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, pem.buf, pem.buflen ) ) != 0 ) { pk_free( pk ); } pem_free( &pem ); return( ret ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #if defined(POLARSSL_PKCS12_C) || defined(POLARSSL_PKCS5_C) ret = pem_read_buffer( &pem, "-----BEGIN ENCRYPTED PRIVATE KEY-----", "-----END ENCRYPTED PRIVATE KEY-----", key, NULL, 0, &len ); if( ret == 0 ) { if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, pem.buf, pem.buflen, pwd, pwdlen ) ) != 0 ) { pk_free( pk ); } pem_free( &pem ); return( ret ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #endif /* POLARSSL_PKCS12_C || POLARSSL_PKCS5_C */ #else ((void) pwd); ((void) pwdlen); #endif /* POLARSSL_PEM_PARSE_C */ /* * At this point we only know it's not a PEM formatted key. Could be any * of the known DER encoded private key formats * * We try the different DER format parsers to see if one passes without * error */ #if defined(POLARSSL_PKCS12_C) || defined(POLARSSL_PKCS5_C) if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, key, keylen, pwd, pwdlen ) ) == 0 ) { return( 0 ); } pk_free( pk ); if( ret == POLARSSL_ERR_PK_PASSWORD_MISMATCH ) { return( ret ); } #endif /* POLARSSL_PKCS12_C || POLARSSL_PKCS5_C */ if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 ) return( 0 ); pk_free( pk ); #if defined(POLARSSL_RSA_C) if( ( pk_info = pk_info_from_type( POLARSSL_PK_RSA ) ) == NULL ) return( POLARSSL_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = pk_init_ctx( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_pkcs1_der( pk_rsa( *pk ), key, keylen ) ) == 0 ) { return( 0 ); } pk_free( pk ); #endif /* POLARSSL_RSA_C */ #if defined(POLARSSL_ECP_C) if( ( pk_info = pk_info_from_type( POLARSSL_PK_ECKEY ) ) == NULL ) return( POLARSSL_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = pk_init_ctx( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_sec1_der( pk_ec( *pk ), key, keylen ) ) == 0 ) { return( 0 ); } pk_free( pk ); #endif /* POLARSSL_ECP_C */ return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT ); }
/* * Parse one or more PEM certificates from a buffer and add them to the chained list */ int x509_crt_parse( x509_crt *chain, const unsigned char *buf, size_t buflen ) { int success = 0, first_error = 0, total_failed = 0; int buf_format = X509_FORMAT_DER; /* * Check for valid input */ if( chain == NULL || buf == NULL ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); /* * Determine buffer content. Buffer contains either one DER certificate or * one or more PEM certificates. */ #if defined(POLARSSL_PEM_PARSE_C) if( strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL ) buf_format = X509_FORMAT_PEM; #endif if( buf_format == X509_FORMAT_DER ) return x509_crt_parse_der( chain, buf, buflen ); #if defined(POLARSSL_PEM_PARSE_C) if( buf_format == X509_FORMAT_PEM ) { int ret; pem_context pem; while( buflen > 0 ) { size_t use_len; pem_init( &pem ); ret = pem_read_buffer( &pem, "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----", buf, NULL, 0, &use_len ); if( ret == 0 ) { /* * Was PEM encoded */ buflen -= use_len; buf += use_len; } else if( ret == POLARSSL_ERR_PEM_BAD_INPUT_DATA ) { return( ret ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { pem_free( &pem ); /* * PEM header and footer were found */ buflen -= use_len; buf += use_len; if( first_error == 0 ) first_error = ret; continue; } else break; ret = x509_crt_parse_der( chain, pem.buf, pem.buflen ); pem_free( &pem ); if( ret != 0 ) { /* * Quit parsing on a memory error */ if( ret == POLARSSL_ERR_X509_MALLOC_FAILED ) return( ret ); if( first_error == 0 ) first_error = ret; total_failed++; continue; } success = 1; } } #endif if( success ) return( total_failed ); else if( first_error ) return( first_error ); else return( POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT ); }
/* * Parse one or more CRLs and add them to the chained list */ int x509_crl_parse( x509_crl *chain, const unsigned char *buf, size_t buflen ) { int ret; size_t len; unsigned char *p, *end; x509_crl *crl; #if defined(POLARSSL_PEM_PARSE_C) size_t use_len; pem_context pem; #endif crl = chain; /* * Check for valid input */ if( crl == NULL || buf == NULL ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); while( crl->version != 0 && crl->next != NULL ) crl = crl->next; /* * Add new CRL on the end of the chain if needed. */ if ( crl->version != 0 && crl->next == NULL) { crl->next = (x509_crl *) polarssl_malloc( sizeof( x509_crl ) ); if( crl->next == NULL ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_MALLOC_FAILED ); } crl = crl->next; x509_crl_init( crl ); } #if defined(POLARSSL_PEM_PARSE_C) pem_init( &pem ); ret = pem_read_buffer( &pem, "-----BEGIN X509 CRL-----", "-----END X509 CRL-----", buf, NULL, 0, &use_len ); if( ret == 0 ) { /* * Was PEM encoded */ buflen -= use_len; buf += use_len; /* * Steal PEM buffer */ p = pem.buf; pem.buf = NULL; len = pem.buflen; pem_free( &pem ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { pem_free( &pem ); return( ret ); } else #endif { /* * nope, copy the raw DER data */ p = (unsigned char *) polarssl_malloc( len = buflen ); if( p == NULL ) return( POLARSSL_ERR_X509_MALLOC_FAILED ); memcpy( p, buf, buflen ); buflen = 0; } crl->raw.p = p; crl->raw.len = len; end = p + len; /* * CertificateList ::= SEQUENCE { * tbsCertList TBSCertList, * signatureAlgorithm AlgorithmIdentifier, * signatureValue BIT STRING } */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_INVALID_FORMAT ); } if( len != (size_t) ( end - p ) ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } /* * TBSCertList ::= SEQUENCE { */ crl->tbs.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_INVALID_FORMAT + ret ); } end = p + len; crl->tbs.len = end - crl->tbs.p; /* * Version ::= INTEGER OPTIONAL { v1(0), v2(1) } * -- if present, MUST be v2 * * signature AlgorithmIdentifier */ if( ( ret = x509_crl_get_version( &p, end, &crl->version ) ) != 0 || ( ret = x509_get_alg_null( &p, end, &crl->sig_oid1 ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } crl->version++; if( crl->version > 2 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_UNKNOWN_VERSION ); } if( ( ret = x509_get_sig_alg( &crl->sig_oid1, &crl->sig_md, &crl->sig_pk ) ) != 0 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_UNKNOWN_SIG_ALG ); } /* * issuer Name */ crl->issuer_raw.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_INVALID_FORMAT + ret ); } if( ( ret = x509_get_name( &p, p + len, &crl->issuer ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } crl->issuer_raw.len = p - crl->issuer_raw.p; /* * thisUpdate Time * nextUpdate Time OPTIONAL */ if( ( ret = x509_get_time( &p, end, &crl->this_update ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } if( ( ret = x509_get_time( &p, end, &crl->next_update ) ) != 0 ) { if ( ret != ( POLARSSL_ERR_X509_INVALID_DATE + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) && ret != ( POLARSSL_ERR_X509_INVALID_DATE + POLARSSL_ERR_ASN1_OUT_OF_DATA ) ) { x509_crl_free( crl ); return( ret ); } } /* * revokedCertificates SEQUENCE OF SEQUENCE { * userCertificate CertificateSerialNumber, * revocationDate Time, * crlEntryExtensions Extensions OPTIONAL * -- if present, MUST be v2 * } OPTIONAL */ if( ( ret = x509_get_entries( &p, end, &crl->entry ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } /* * crlExtensions EXPLICIT Extensions OPTIONAL * -- if present, MUST be v2 */ if( crl->version == 2 ) { ret = x509_get_crl_ext( &p, end, &crl->crl_ext ); if( ret != 0 ) { x509_crl_free( crl ); return( ret ); } } if( p != end ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } end = crl->raw.p + crl->raw.len; /* * signatureAlgorithm AlgorithmIdentifier, * signatureValue BIT STRING */ if( ( ret = x509_get_alg_null( &p, end, &crl->sig_oid2 ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } if( crl->sig_oid1.len != crl->sig_oid2.len || memcmp( crl->sig_oid1.p, crl->sig_oid2.p, crl->sig_oid1.len ) != 0 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_SIG_MISMATCH ); } if( ( ret = x509_get_sig( &p, end, &crl->sig ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } if( p != end ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } if( buflen > 0 ) { crl->next = (x509_crl *) polarssl_malloc( sizeof( x509_crl ) ); if( crl->next == NULL ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_MALLOC_FAILED ); } crl = crl->next; x509_crl_init( crl ); return( x509_crl_parse( crl, buf, buflen ) ); } return( 0 ); }