/* * Return 1 if the certificate is revoked, or 0 otherwise. */ int x509_crt_revoked( const x509_crt *crt, const x509_crl *crl ) { const x509_crl_entry *cur = &crl->entry; while( cur != NULL && cur->serial.len != 0 ) { if( crt->serial.len == cur->serial.len && memcmp( crt->serial.p, cur->serial.p, crt->serial.len ) == 0 ) { if( x509_time_expired( &cur->revocation_date ) ) return( 1 ); } cur = cur->next; } return( 0 ); }
static int __pkcs11h_crypto_mbedtls_certificate_get_expiration ( IN void * const global_data, IN const unsigned char * const blob, IN const size_t blob_size, OUT time_t * const expiration ) { x509_crt x509; (void)global_data; /*_PKCS11H_ASSERT (global_data!=NULL); NOT NEEDED*/ _PKCS11H_ASSERT (blob!=NULL); _PKCS11H_ASSERT (expiration!=NULL); *expiration = (time_t)0; memset(&x509, 0, sizeof(x509)); if (0 != x509_crt_parse (&x509, blob, blob_size)) { goto cleanup; } if (0 == x509_time_expired(&x509.valid_to)) { struct tm tm1; memset (&tm1, 0, sizeof (tm1)); tm1.tm_year = x509.valid_to.year - 1900; tm1.tm_mon = x509.valid_to.mon - 1; tm1.tm_mday = x509.valid_to.day; tm1.tm_hour = x509.valid_to.hour - 1; tm1.tm_min = x509.valid_to.min - 1; tm1.tm_sec = x509.valid_to.sec - 1; *expiration = mktime (&tm1); *expiration += (int)(mktime (localtime (expiration)) - mktime (gmtime (expiration))); } cleanup: x509_crt_free(&x509); return *expiration != (time_t)0; }
char *test_SSL_verify_cert() { x509_crt crt; memset( &crt, 0, sizeof crt ); x509_crt ca_crt; memset( &ca_crt, 0, sizeof ca_crt ); x509_crl crl; memset( &crl, 0, sizeof crl ); int ret = 0; ret =x509_crt_parse_file( &crt, "tests/ca/certs/m2-cert.pem" ); mu_assert(ret == 0, "failed to parse cert m2-cert.pem"); ret =x509_crt_parse_file( &ca_crt, "tests/ca/none.pem" ); mu_assert(ret != 0, "failed to fail on non-existent pem none.pem"); ret =x509_crt_parse_file( &ca_crt, "tests/ca/cacert.pem" ); mu_assert(ret == 0, "failed to parse cert cacert.pem"); ret =x509_crl_parse_file( &crl, "tests/ca/crl.pem" ); mu_assert(ret == 0, "failed to parse cert crl.pem"); /* * Validate the cert. Since these certs are only valid within a certain time period, this test * will fail when the current time is outside this period. To avoid false failures (eg. when * building/testing this version of the software in the distant future), adjust the expected * test outcome accordingly. However, log the failure to stderr so that the maintainer can * detect the expiry of the cert, and generate/commit a new one from time to time. */ int flags = 0; ret =x509_crt_verify( &crt, &ca_crt, NULL, NULL, &flags, NULL, NULL); if ( ret ) { char buf[1024]; buf[0] = 0; polarssl_strerror( ret, buf, sizeof buf ); fprintf( stderr, "*** x509_crt_verify of m2-cert.pem: %d: %s\n", ret, buf ); } int valid_from = x509_time_expired( &crt.valid_from ); int valid_to = x509_time_expired( &crt.valid_to ); int expected = 0; if ( valid_from == BADCERT_EXPIRED && valid_to == BADCERT_EXPIRED ) { /* * This cert hasn't yet become active, or has already expired; expect * X509 cert failure (-0x2700) */ fprintf( stderr, "*** x509_crt_verify WILL FAIL because current data is outside: valid_from '%d/%d/%d %d:%d:%d': %d, valid_to '%d/%d/%d %d:%d:%d': %d\n", crt.valid_from.year, crt.valid_from.mon, crt.valid_from.day, crt.valid_from.hour, crt.valid_from.min, crt.valid_from.sec, valid_from, crt.valid_to .year, crt.valid_to .mon, crt.valid_to .day, crt.valid_to .hour, crt.valid_to .min, crt.valid_to .sec, valid_to ); fprintf( stderr, "*** If this is the currently supported version, generate and commit a new tests/ca/m2-cert.pem with valid dates\n" ); expected = POLARSSL_ERR_X509_CERT_VERIFY_FAILED; } mu_assert(ret == expected, "failed to verify cert m2-cert.pem"); x509_crt_free( &crt ); x509_crt_free( &ca_crt ); x509_crl_free( &crl ); return NULL; }
static int x509_crt_verify_child( x509_crt *child, x509_crt *parent, x509_crt *trust_ca, x509_crl *ca_crl, int path_cnt, int *flags, int (*f_vrfy)(void *, x509_crt *, int, int *), void *p_vrfy ) { int ret; int parent_flags = 0; unsigned char hash[POLARSSL_MD_MAX_SIZE]; x509_crt *grandparent; const md_info_t *md_info; if( x509_time_expired( &child->valid_to ) ) *flags |= BADCERT_EXPIRED; md_info = md_info_from_type( child->sig_md ); if( md_info == NULL ) { /* * Cannot check 'unknown' hash */ *flags |= BADCERT_NOT_TRUSTED; } else { md( md_info, child->tbs.p, child->tbs.len, hash ); if( pk_can_do( &parent->pk, child->sig_pk ) == 0 || pk_verify( &parent->pk, child->sig_md, hash, md_info->size, child->sig.p, child->sig.len ) != 0 ) { *flags |= BADCERT_NOT_TRUSTED; } } #if defined(POLARSSL_X509_CRL_PARSE_C) /* Check trusted CA's CRL for the given crt */ *flags |= x509_crt_verifycrl(child, parent, ca_crl); #endif grandparent = parent->next; while( grandparent != NULL ) { if( grandparent->version == 0 || grandparent->ca_istrue == 0 || parent->issuer_raw.len != grandparent->subject_raw.len || memcmp( parent->issuer_raw.p, grandparent->subject_raw.p, parent->issuer_raw.len ) != 0 ) { grandparent = grandparent->next; continue; } break; } if( grandparent != NULL ) { /* * Part of the chain */ ret = x509_crt_verify_child( parent, grandparent, trust_ca, ca_crl, path_cnt + 1, &parent_flags, f_vrfy, p_vrfy ); if( ret != 0 ) return( ret ); } else { ret = x509_crt_verify_top( parent, trust_ca, ca_crl, path_cnt + 1, &parent_flags, f_vrfy, p_vrfy ); if( ret != 0 ) return( ret ); } /* child is verified to be a child of the parent, call verify callback */ if( NULL != f_vrfy ) if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 ) return( ret ); *flags |= parent_flags; return( 0 ); }
static int x509_crt_verify_top( x509_crt *child, x509_crt *trust_ca, x509_crl *ca_crl, int path_cnt, int *flags, int (*f_vrfy)(void *, x509_crt *, int, int *), void *p_vrfy ) { int ret; int ca_flags = 0, check_path_cnt = path_cnt + 1; unsigned char hash[POLARSSL_MD_MAX_SIZE]; const md_info_t *md_info; if( x509_time_expired( &child->valid_to ) ) *flags |= BADCERT_EXPIRED; /* * Child is the top of the chain. Check against the trust_ca list. */ *flags |= BADCERT_NOT_TRUSTED; md_info = md_info_from_type( child->sig_md ); if( md_info == NULL ) { /* * Cannot check 'unknown', no need to try any CA */ trust_ca = NULL; } else md( md_info, child->tbs.p, child->tbs.len, hash ); while( trust_ca != NULL ) { if( trust_ca->version == 0 || child->issuer_raw.len != trust_ca->subject_raw.len || memcmp( child->issuer_raw.p, trust_ca->subject_raw.p, child->issuer_raw.len ) != 0 ) { trust_ca = trust_ca->next; continue; } /* * Reduce path_len to check against if top of the chain is * the same as the trusted CA */ if( child->subject_raw.len == trust_ca->subject_raw.len && memcmp( child->subject_raw.p, trust_ca->subject_raw.p, child->issuer_raw.len ) == 0 ) { check_path_cnt--; } if( trust_ca->max_pathlen > 0 && trust_ca->max_pathlen < check_path_cnt ) { trust_ca = trust_ca->next; continue; } if( pk_can_do( &trust_ca->pk, child->sig_pk ) == 0 || pk_verify( &trust_ca->pk, child->sig_md, hash, md_info->size, child->sig.p, child->sig.len ) != 0 ) { trust_ca = trust_ca->next; continue; } /* * Top of chain is signed by a trusted CA */ *flags &= ~BADCERT_NOT_TRUSTED; break; } /* * If top of chain is not the same as the trusted CA send a verify request * to the callback for any issues with validity and CRL presence for the * trusted CA certificate. */ if( trust_ca != NULL && ( child->subject_raw.len != trust_ca->subject_raw.len || memcmp( child->subject_raw.p, trust_ca->subject_raw.p, child->issuer_raw.len ) != 0 ) ) { #if defined(POLARSSL_X509_CRL_PARSE_C) /* Check trusted CA's CRL for the chain's top crt */ *flags |= x509_crt_verifycrl( child, trust_ca, ca_crl ); #else ((void) ca_crl); #endif if( x509_time_expired( &trust_ca->valid_to ) ) ca_flags |= BADCERT_EXPIRED; if( NULL != f_vrfy ) { if( ( ret = f_vrfy( p_vrfy, trust_ca, path_cnt + 1, &ca_flags ) ) != 0 ) return( ret ); } } /* Call callback on top cert */ if( NULL != f_vrfy ) { if( ( ret = f_vrfy(p_vrfy, child, path_cnt, flags ) ) != 0 ) return( ret ); } *flags |= ca_flags; return( 0 ); }
/* * Check that the given certificate is valid according to the CRL. */ static int x509_crt_verifycrl( x509_crt *crt, x509_crt *ca, x509_crl *crl_list) { int flags = 0; unsigned char hash[POLARSSL_MD_MAX_SIZE]; const md_info_t *md_info; if( ca == NULL ) return( flags ); /* * TODO: What happens if no CRL is present? * Suggestion: Revocation state should be unknown if no CRL is present. * For backwards compatibility this is not yet implemented. */ while( crl_list != NULL ) { if( crl_list->version == 0 || crl_list->issuer_raw.len != ca->subject_raw.len || memcmp( crl_list->issuer_raw.p, ca->subject_raw.p, crl_list->issuer_raw.len ) != 0 ) { crl_list = crl_list->next; continue; } /* * Check if CRL is correctly signed by the trusted CA */ md_info = md_info_from_type( crl_list->sig_md ); if( md_info == NULL ) { /* * Cannot check 'unknown' hash */ flags |= BADCRL_NOT_TRUSTED; break; } md( md_info, crl_list->tbs.p, crl_list->tbs.len, hash ); if( pk_can_do( &ca->pk, crl_list->sig_pk ) == 0 || pk_verify( &ca->pk, crl_list->sig_md, hash, md_info->size, crl_list->sig.p, crl_list->sig.len ) != 0 ) { flags |= BADCRL_NOT_TRUSTED; break; } /* * Check for validity of CRL (Do not drop out) */ if( x509_time_expired( &crl_list->next_update ) ) flags |= BADCRL_EXPIRED; /* * Check if certificate is revoked */ if( x509_crt_revoked(crt, crl_list) ) { flags |= BADCERT_REVOKED; break; } crl_list = crl_list->next; } return flags; }