| RSA BSAFE Micro Edition Suite |
Streamlined security for mobile and embedded devices |
 
![]() |
/* $Id: verify_cb.c,v 1.31.6.1 2005/11/22 00:30:04 lmalmborg Exp $ */ /* * Copyright (C) 2002 RSA Security Inc. * * This file shall only be used to demonstrate how to interface to an * RSA Security Inc. licensed development product. * * You have a royalty-free right to use, reproduce and distribute this * demonstration file, provided that you agree that RSA Security Inc. * has no warranty, implied or otherwise, or liability for this * demonstration file (including any modified version). This software * is provided "as is" without warranties or representations of any * kind. RSA Security disclaims all conditions and warranties, statutory * and otherwise, both express and implied, with respect to the software, * its quality and performance, including but not limited to, all * implied warranties of merchantability, fitness for a particular * purpose, title and noninfringement of third party rights. Without * limiting the foregoing, RSA Security does not warrant that the * software is error-free or that errors in the product will be * corrected. You agree that RSA Security shall not be liable for any * direct, indirect, incidental, special, consequential, punitive or * other damages whatsoever resulting from your use of this software * or any modified version. * * */ #include <time.h> #include "verify_cb.h" #define MAX_SSLCERT_NAME_BUF_LEN 128 #ifndef NO_VERIFICATION /* * Include the Certification Authority (CA) list which contains only * the subject name and public key data of certificates as the full certificate * is not required for verification (to reduce data size). */ #ifdef TEST_CA #include "tcalist.h" #else #include "calist.h" #endif static int CA_data_init = 0; #endif /* !NO_VERIFICATION */ #ifdef SSLC_SMALL_CODE #define NO_PRINT_SSLCERT_NAME #endif int v_cb_dummy(SSL * ssl, SSLCERT *x[], int num, char *arg, long *verify_result) { /* Accept all certificates without checking */ return (1); } #ifndef NO_VERIFICATION int v_cb(SSL * ssl, SSLCERT *x[], int num, char *arg, long *verify_result) { int ret = 0; /* Function return code, initialized to failure */ int err; int i; int idx; unsigned int ca_idx; SSLCERT_NAME *xn; SSLCERT_NAME *sn; EVP_PKEY *pubkey = NULL; char *p; #ifndef NO_STDIO #ifndef NO_PRINT_SSLCERT_NAME char buf[MAX_SSLCERT_NAME_BUF_LEN] = {'\0'}; #endif /* NO_PRINT_SSLCERT_NAME */ #endif /* NO_STDIO */ #ifdef SSLC_SMALL_CODE unsigned char *certTime = NULL; long timeLen = 0; int result = 0; unsigned int time_encoding = SSLCERT_ENCODING_ASN1_UTCTIME; unsigned int now = 0; /* Current time in seconds since 1 Jan, 1970 */ #endif /* SSLC_SMALL_CODE */ unsigned int critical; /* Maximum path length allowed */ unsigned long path_constraint=10; int ca_constraint; /* * For this callback, the current_cert is undefined. get_cert returns the * 'leaf' certificate. */ if (num == 0) { #ifndef NO_STDIO fprintf(stderr, "No certificates\n"); fflush(stderr); #endif goto end; } /* * Convert the binary subject names into usable #SSLCERT_NAME objects so * they can be compared with the objects in the certificates */ if (!CA_data_init) { for (ca_idx = 0; ca_idx < CA_DATA_NUM; ca_idx++) { unsigned char *pp; pp = CA_data[ca_idx].namedata; if (SSLCERT_NAME_from_binary(&CA_data[ca_idx].name, &pp, CA_data[ca_idx].namedata_len) == NULL) { #ifndef NO_STDIO fprintf(stderr, "Error - failed to convert CA name data\n"); fflush(stderr); #endif return (0); } } CA_data_init = 1; } #ifndef NO_STDIO fprintf(stderr, "Verify information\n"); fprintf(stderr, "There are %d certs in the chain\n", num); fflush(stderr); #endif /************************************************/ /* VERIFICATION CODE */ /************************************************/ /* Retrieve the first certificate and attempt to find the issuer */ idx = 0; for (;;) { xn = SSLCERT_get_issuer_name(x[idx]); #ifndef NO_STDIO #ifndef NO_PRINT_SSLCERT_NAME fprintf(stdout, "Index: %d \nIssuer: %s\n", idx, SSLCERT_NAME_oneline(xn,buf,MAX_SSLCERT_NAME_BUF_LEN)); fprintf(stdout, "Subject: %s\n", SSLCERT_NAME_oneline(SSLCERT_get_subject_name(x[idx]),buf, MAX_SSLCERT_NAME_BUF_LEN)); fflush(stdout); #endif /* NO_PRINT_SSLCERT_NAME */ #endif /* NO_STDIO */ /* Check for the issuer in the CA list */ for (ca_idx = 0; ca_idx < CA_DATA_NUM; ca_idx++) { if (SSLCERT_NAME_cmp(CA_data[ca_idx].name, xn) == 0) { /* A CA was located in the list */ goto verify; } } /* * Indicates the issuer was not found in the CA list. Check the next * certificate in the certificate chain. */ if (idx + 1 >= num) { /* * The last certificate has been reached, and therefore the * certificates cannot be verified. Return. */ #ifndef NO_STDIO fprintf(stderr, "Unable to verify certificate\n"); fflush(stderr); #endif goto end; } else { sn = SSLCERT_get_subject_name(x[idx + 1]); if (SSLCERT_NAME_cmp(xn, sn) != 0) { /* * The next certificate in the chain is not the signer of the * previous one. As the SSL implementation was not correct it * will fail at this point. */ #ifndef NO_STDIO fprintf(stderr, "Certificate chain is non-standard\n"); fflush(stderr); #endif goto end; } /* Point at this new certificate */ idx++; } } verify: /* * At this point, certificates x[0] .. x[idx] need to verified. * The CA information is in CA_data[ca_idx]. Verify x[idx] with * CA_data[ca_idx], x[idx-1] with x[idx], x[idx-2] with x[idx-1] * ... x[0] with x[1]. */ #ifndef NO_STDIO fprintf(stdout, "******* ca_idx=%d idx=%d\n", ca_idx, idx); fflush(stdout); #endif /* Load the CA key */ p = (char *) CA_data[ca_idx].pkey; if ((SSLCERT_PKEY_from_PUBKEY_binary(EVP_PKEY_RSA, &pubkey, (unsigned char **) &p, CA_data[ca_idx].pkey_len)) == NULL) { goto end; } err = SSLCERT_verify(x[idx], pubkey); SSLCERT_PKEY_free(pubkey); pubkey = NULL; if (!err) { #ifndef NO_STDIO fprintf(stderr, "Failed to verify the certificate with CA key\n"); fflush(stderr); #endif goto end; } for (i = idx; i >= 0; i--) { /* * Check the basic constraints on all certificates in the chain * except for the trusted CA and the leaf certificate */ if ((i > 0) && (SSLCERT_get_basic_constraints_int(x[i], &critical, &path_constraint, &ca_constraint) == 1)) { #ifndef NO_STDIO fprintf(stderr,"Basic Constraints: %s : %s : MaxLen:%ld\n", critical ? "critical" : "not crit", ca_constraint ? "ca" : "no ca", path_constraint); fflush(stderr); #endif /* If the certificate is not a CA then verification fails */ if (!ca_constraint) { #ifndef NO_STDIO fprintf(stderr, "Certificate at index %d is not a CA\n", i); fflush(stderr); #endif goto end; } /* * Otherwise if the number of certificates in the remainder of the * chain exceeds the allowed length given in the path_constraint * then verification fails. Note that a path length of zero * indicates the leaf certificate must be next. */ else if (path_constraint + 1 < (unsigned int)i ) { #ifndef NO_STDIO fprintf(stderr, "Path longer than allowed by CA (pathlen:%d)\n", i-1); fflush(stderr); #endif goto end; } } #ifndef NO_STDIO #ifndef NO_PRINT_SSLCERT_NAME fprintf(stdout, "Index: %d, Issuer: %s\n", i, SSLCERT_NAME_oneline(SSLCERT_get_issuer_name(x[i]),buf, MAX_SSLCERT_NAME_BUF_LEN)); fflush(stdout); #endif /* NO_PRINT_SSLCERT_NAME */ #endif /* NO_STDIO */ /* * Ensure that the next certificate in the chained is signed * correctly */ if (i > 0) { if ((pubkey = SSLCERT_get_pubkey(x[i])) == NULL) { goto end; } if (!SSLCERT_verify(x[i - 1], pubkey)) { #ifndef NO_STDIO fprintf(stderr, "Verify of certificate failure\n"); fflush(stderr); #endif goto end; } } #ifdef SSLC_SMALL_CODE { /* * Check the certificate for time validity. Ensure notAfter and * notBefore are satisfied. */ now = time(NULL); /* First check notAfter */ if (SSLCERT_get_notAfter(x[i], &time_encoding, &certTime, &timeLen) == 1) { /* Check if the notAfter date is valid */ if (SSLCERT_compare_ASN1_time((int)time_encoding, certTime, now, &result) == 1) { if (result == 1) { /* notAfter time is ok */ } else { #ifndef NO_STDIO fprintf(stderr, "certificate %d has expired\n", i); fflush(stderr); #endif goto end; } } else { #ifndef NO_STDIO fprintf(stderr, "Error comparing notAfter time\n"); fflush(stderr); #endif goto end; } } else { #ifndef NO_STDIO fprintf(stderr, "Error getting notAfter data, certificate: %d", i); fflush(stderr); #endif goto end; } /* Check notBefore */ if (SSLCERT_get_notBefore(x[i], &time_encoding, &certTime, &timeLen) == 1) { if (SSLCERT_compare_ASN1_time((int)time_encoding, certTime, now, &result) == 1) { if (result == -1) { /* notBefore time is ok */ } else { #ifndef NO_STDIO fprintf(stderr, "certificate %d is not yet valid\n", i); fflush(stderr); #endif goto end; } } else { #ifndef NO_STDIO fprintf(stderr, "Error comparing notBefore time\n"); fflush(stderr); #endif goto end; } } else { #ifndef NO_STDIO fprintf(stderr, "Error getting notBefore data, certificate: %d", i); fflush(stderr); #endif goto end; } } #endif /* SSLC_SMALL_CODE */ } /* Everything seems to be OK */ ret = 1; end: return(ret); } void v_cb_cleanup(void) { unsigned int ca_idx; for (ca_idx = 0; ca_idx < CA_DATA_NUM; ca_idx++) { if (CA_data[ca_idx].name != NULL) { SSLCERT_NAME_free(CA_data[ca_idx].name); } } } #endif /* !NO_VERIFICATION */