diff options
Diffstat (limited to 'lib/x509_verify.c')
-rw-r--r-- | lib/x509_verify.c | 258 |
1 files changed, 170 insertions, 88 deletions
diff --git a/lib/x509_verify.c b/lib/x509_verify.c index 346b43405e..6d6915e617 100644 --- a/lib/x509_verify.c +++ b/lib/x509_verify.c @@ -30,57 +30,110 @@ /* TIME functions */ + +/* The mktime_utc function is due to Russ Allbery (rra@stanford.edu), + * who placed it under public domain: + */ + +/* The number of days in each month. + */ +static const int MONTHDAYS[] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + + /* Whether a given year is a leap year. */ +#define ISLEAP(year) \ + (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0)) + +/* + ** Given a struct tm representing a calendar time in UTC, convert it to + ** seconds since epoch. Returns (time_t) -1 if the time is not + ** convertable. Note that this function does not canonicalize the provided + ** struct tm, nor does it allow out of range values or years before 1970. + */ +static time_t mktime_utc(const struct tm *tm) +{ + time_t result = 0; + int i; + +/* We do allow some ill-formed dates, but we don't do anything special + * with them and our callers really shouldn't pass them to us. Do + * explicitly disallow the ones that would cause invalid array accesses + * or other algorithm problems. + */ + if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 70) + return (time_t) - 1; + +/* Convert to a time_t. + */ + for (i = 1970; i < tm->tm_year + 1900; i++) + result += 365 + ISLEAP(i); + for (i = 0; i < tm->tm_mon; i++) + result += MONTHDAYS[i]; + if (tm->tm_mon > 1 && ISLEAP(tm->tm_year + 1900)) + result++; + result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour; + result = 60 * result + tm->tm_min; + result = 60 * result + tm->tm_sec; + return result; +} + + time_t _gnutls_utcTime2gtime(char *ttime) { char xx[3]; struct tm etime; time_t ret; + if (strlen( ttime) < 10) { + gnutls_assert(); + return (time_t) -1; + } xx[2] = 0; /* get the year */ memcpy(xx, ttime, 2); /* year */ etime.tm_year = atoi(xx); - ttime+=2; + ttime += 2; if (etime.tm_year > 49) etime.tm_year += 1900; else etime.tm_year += 2000; - etime.tm_year-=1900; /* well we need to find something - * better than mktime(); - */ + etime.tm_year -= 1900; /* well we need to find something + * better than mktime(); + */ /* get the month */ memcpy(xx, ttime, 2); /* month */ etime.tm_mon = atoi(xx) - 1; - ttime+=2; - + ttime += 2; + /* get the day */ memcpy(xx, ttime, 2); /* day */ etime.tm_mday = atoi(xx); - ttime+=2; - + ttime += 2; + /* get the hour */ memcpy(xx, ttime, 2); /* hour */ etime.tm_hour = atoi(xx); - ttime+=2; - + ttime += 2; + /* get the minutes */ memcpy(xx, ttime, 2); /* minutes */ etime.tm_min = atoi(xx); - ttime+=2; - + ttime += 2; + etime.tm_isdst = -1; etime.tm_sec = 0; - - ret = mktime(&etime); + + ret = mktime_utc(&etime); return ret; } @@ -91,6 +144,11 @@ time_t _gnutls_generalTime2gtime(char *ttime) struct tm etime; time_t ret; + if (strlen( ttime) < 12) { + gnutls_assert(); + return (time_t) -1; + } + if (strchr(ttime, 'Z') == 0) { gnutls_assert(); /* sorry we don't support it yet @@ -103,9 +161,9 @@ time_t _gnutls_generalTime2gtime(char *ttime) */ memcpy(xx, ttime, 4); /* year */ etime.tm_year = atoi(xx); - ttime+=2; + ttime += 2; - etime.tm_year-=1900; + etime.tm_year -= 1900; xx[2] = 0; @@ -113,27 +171,27 @@ time_t _gnutls_generalTime2gtime(char *ttime) */ memcpy(xx, ttime, 2); /* month */ etime.tm_mon = atoi(xx) - 1; - ttime+=2; - + ttime += 2; + /* get the day */ memcpy(xx, ttime, 2); /* day */ etime.tm_mday = atoi(xx); - ttime+=2; - + ttime += 2; + /* get the hour */ memcpy(xx, ttime, 2); /* hour */ etime.tm_hour = atoi(xx); - ttime+=2; - + ttime += 2; + /* get the minutes */ memcpy(xx, ttime, 2); /* minutes */ etime.tm_min = atoi(xx); - ttime+=2; - - ret = mktime(&etime); + ttime += 2; + + ret = mktime_utc(&etime); etime.tm_isdst = -1; etime.tm_sec = 0; @@ -146,8 +204,8 @@ time_t _gnutls_generalTime2gtime(char *ttime) static int check_if_expired(gnutls_cert * cert) { CertificateStatus ret = GNUTLS_CERT_EXPIRED; - - if (cert->expiration_time == (time_t)(-1)) + + if (cert->expiration_time == (time_t) (-1)) return GNUTLS_CERT_INVALID; /* get the issuer of 'cert' @@ -161,21 +219,24 @@ static int check_if_expired(gnutls_cert * cert) /* Return 0 or INVALID, if the issuer is a CA, * or not. */ -static int check_if_ca(const gnutls_cert * cert, const gnutls_cert* issuer) +static int check_if_ca(const gnutls_cert * cert, + const gnutls_cert * issuer) { CertificateStatus ret = GNUTLS_CERT_INVALID; - + /* Check if the issuer is the same with the * certificate. This is added in order for trusted * certificates to be able to verify themselves. */ if (cert->raw.size == issuer->raw.size) { - if ( memcmp( cert->raw.data, issuer->raw.data, cert->raw.size)==0) { + if (memcmp + (cert->raw.data, issuer->raw.data, + cert->raw.size) == 0) { return 0; } } - if (issuer->CA==1) { + if (issuer->CA == 1) { ret = 0; } else gnutls_assert(); @@ -185,7 +246,7 @@ static int check_if_ca(const gnutls_cert * cert, const gnutls_cert* issuer) -void _gnutls_int2str(int k, char* data); +void _gnutls_int2str(int k, char *data); #define MAX_DN_ELEM 1024 @@ -206,11 +267,13 @@ int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert) /* get the issuer of 'cert' */ - if ((result=asn1_create_structure(_gnutls_get_pkix(), "PKIX1.Certificate", &c2, "certificate2")) != ASN_OK) { + if ((result = + asn1_create_structure(_gnutls_get_pkix(), "PKIX1.Certificate", + &c2, "certificate2")) != ASN_OK) { gnutls_assert(); return _gnutls_asn2err(result); } - + result = asn1_get_der(c2, cert->raw.data, cert->raw.size); if (result != ASN_OK) { /* couldn't decode DER */ @@ -218,18 +281,21 @@ int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert) asn1_delete_structure(c2); return _gnutls_asn2err(result); } - + /* get the 'subject' info of 'issuer_cert' */ - if ((result=asn1_create_structure(_gnutls_get_pkix(), "PKIX1.Certificate", &c3, "certificate2")) != ASN_OK) { + if ((result = + asn1_create_structure(_gnutls_get_pkix(), "PKIX1.Certificate", + &c3, "certificate2")) != ASN_OK) { gnutls_assert(); asn1_delete_structure(c2); return _gnutls_asn2err(result); } - - result = asn1_get_der(c3, issuer_cert->raw.data, issuer_cert->raw.size); + + result = + asn1_get_der(c3, issuer_cert->raw.data, issuer_cert->raw.size); if (result != ASN_OK) { /* couldn't decode DER */ gnutls_assert(); @@ -237,51 +303,57 @@ int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert) return _gnutls_asn2err(result); } - - _gnutls_str_cpy( tmpstr, sizeof(tmpstr), "certificate2.tbsCertificate.issuer"); - result = asn1_get_start_end_der( c2, cert->raw.data, cert->raw.size, - tmpstr, &start1, &end1); - asn1_delete_structure( c2); - - if (result!=ASN_OK) { + + _gnutls_str_cpy(tmpstr, sizeof(tmpstr), + "certificate2.tbsCertificate.issuer"); + result = + asn1_get_start_end_der(c2, cert->raw.data, cert->raw.size, + tmpstr, &start1, &end1); + asn1_delete_structure(c2); + + if (result != ASN_OK) { gnutls_assert(); - asn1_delete_structure( c3); + asn1_delete_structure(c3); return _gnutls_asn2err(result); } - + len1 = end1 - start1 + 1; - - _gnutls_str_cpy( tmpstr, sizeof(tmpstr), "certificate2.tbsCertificate.subject"); - result = asn1_get_start_end_der( c3, issuer_cert->raw.data, issuer_cert->raw.size, - tmpstr, &start2, &end2); - asn1_delete_structure( c3); - - if (result!=ASN_OK) { + + _gnutls_str_cpy(tmpstr, sizeof(tmpstr), + "certificate2.tbsCertificate.subject"); + result = + asn1_get_start_end_der(c3, issuer_cert->raw.data, + issuer_cert->raw.size, tmpstr, &start2, + &end2); + asn1_delete_structure(c3); + + if (result != ASN_OK) { gnutls_assert(); return _gnutls_asn2err(result); } - + len2 = end2 - start2 + 1; /* The error code returned does not really matter * here. - */ - if (len1!=len2) { + */ + if (len1 != len2) { gnutls_assert(); return GNUTLS_E_UNKNOWN_ERROR; } - if (memcmp( &issuer_cert->raw.data[start2], - &cert->raw.data[start1], len1) != 0) { + if (memcmp(&issuer_cert->raw.data[start2], + &cert->raw.data[start1], len1) != 0) { gnutls_assert(); return GNUTLS_E_UNKNOWN_ERROR; } - + /* they match */ return 0; } -static gnutls_cert *find_issuer(gnutls_cert * cert, gnutls_cert * trusted_cas, int tcas_size) +static gnutls_cert *find_issuer(gnutls_cert * cert, + gnutls_cert * trusted_cas, int tcas_size) { int i; @@ -300,8 +372,10 @@ static gnutls_cert *find_issuer(gnutls_cert * cert, gnutls_cert * trusted_cas, i /* ret_trust is the value to return when the certificate chain is ok * ret_else is the value to return otherwise. */ -int gnutls_verify_certificate2(gnutls_cert * cert, gnutls_cert * trusted_cas, int tcas_size, - void *CRLs, int crls_size, int ret_trust, int ret_else) +int gnutls_verify_certificate2(gnutls_cert * cert, + gnutls_cert * trusted_cas, int tcas_size, + void *CRLs, int crls_size, int ret_trust, + int ret_else) { /* CRL is ignored for now */ @@ -323,22 +397,22 @@ int gnutls_verify_certificate2(gnutls_cert * cert, gnutls_cert * trusted_cas, in return ret_else; } - ret = check_if_ca( cert, issuer); + ret = check_if_ca(cert, issuer); if (ret != 0) { gnutls_assert(); - return ret_else|GNUTLS_CERT_INVALID; + return ret_else | GNUTLS_CERT_INVALID; } - ret = check_if_expired( issuer); + ret = check_if_expired(issuer); if (ret != 0) { gnutls_assert(); return ret_else | ret; } - - ret = gnutls_x509_verify_signature(cert, issuer); - if (ret != 0) { - gnutls_assert(); - return ret_else|GNUTLS_CERT_INVALID; + + ret = gnutls_x509_verify_signature(cert, issuer); + if (ret != 0) { + gnutls_assert(); + return ret_else | GNUTLS_CERT_INVALID; } /* FIXME: Check CRL --not done yet. @@ -361,18 +435,20 @@ int gnutls_verify_certificate2(gnutls_cert * cert, gnutls_cert * trusted_cas, in /* This function verifies a X.509 certificate list. The certificate list should * lead to a trusted CA in order to be trusted. */ -int _gnutls_x509_verify_certificate( gnutls_cert * certificate_list, - int clist_size, gnutls_cert * trusted_cas, int tcas_size, void *CRLs, - int crls_size) +int _gnutls_x509_verify_certificate(gnutls_cert * certificate_list, + int clist_size, + gnutls_cert * trusted_cas, + int tcas_size, void *CRLs, + int crls_size) { int i = 0, ret; - CertificateStatus status=0; + CertificateStatus status = 0; - if ( clist_size == 0) { + if (clist_size == 0) { return GNUTLS_E_NO_CERTIFICATE_FOUND; } - ret = check_if_expired( &certificate_list[0]); + ret = check_if_expired(&certificate_list[0]); if (ret != 0) { gnutls_assert(); status |= ret; @@ -383,13 +459,17 @@ int _gnutls_x509_verify_certificate( gnutls_cert * certificate_list, if (i + 1 >= clist_size) break; - if ((ret = gnutls_verify_certificate2(&certificate_list[i], &certificate_list[i + 1], - 1, NULL, 0, 0, GNUTLS_CERT_INVALID)) != 0) { - /* - * We only accept the first certificate to be - * expired, revoked etc. If any of the certificates in the - * certificate chain is expired then the certificate - * is not valid. + if ((ret = + gnutls_verify_certificate2(&certificate_list[i], + &certificate_list[i + 1], + 1, NULL, 0, 0, + GNUTLS_CERT_INVALID)) != + 0) { + /* + * We only accept the first certificate to be + * expired, revoked etc. If any of the certificates in the + * certificate chain is expired then the certificate + * is not valid. */ if (ret > 0) { gnutls_assert(); @@ -404,12 +484,14 @@ int _gnutls_x509_verify_certificate( gnutls_cert * certificate_list, /* Now verify the last certificate in the certificate path * against the trusted CA certificate list. - * + * * If no CAs are present returns NOT_TRUSTED. Thus works * in self signed etc certificates. */ - ret = gnutls_verify_certificate2(&certificate_list[i], trusted_cas, tcas_size, - CRLs, crls_size, 0, GNUTLS_CERT_NOT_TRUSTED); + ret = + gnutls_verify_certificate2(&certificate_list[i], trusted_cas, + tcas_size, CRLs, crls_size, 0, + GNUTLS_CERT_NOT_TRUSTED); if (ret > 0) { /* if the last certificate in the certificate @@ -424,7 +506,7 @@ int _gnutls_x509_verify_certificate( gnutls_cert * certificate_list, gnutls_assert(); return ret; } - + /* if we got here, then it's trusted. */ return status; |