/* * Checks if CA a is trusted by CA b */ bool trusted_ca(chunk_t a, chunk_t b, int *pathlen) { bool match = FALSE; char abuf[ASN1_BUF_LEN], bbuf[ASN1_BUF_LEN]; dntoa(abuf, ASN1_BUF_LEN, a); dntoa(bbuf, ASN1_BUF_LEN, b); DBG(DBG_X509 | DBG_CONTROLMORE, DBG_log(" trusted_ca called with a=%s b=%s", abuf, bbuf)); /* no CA b specified -> any CA a is accepted */ if (b.ptr == NULL) { *pathlen = (a.ptr == NULL) ? 0 : MAX_CA_PATH_LEN; return TRUE; } /* no CA a specified -> trust cannot be established */ if (a.ptr == NULL) { *pathlen = MAX_CA_PATH_LEN; return FALSE; } *pathlen = 0; /* CA a equals CA b -> we have a match */ if (same_dn(a, b)) return TRUE; /* CA a might be a subordinate CA of b */ lock_authcert_list("trusted_ca"); while ((*pathlen)++ < MAX_CA_PATH_LEN) { x509cert_t *cacert = get_authcert(a, empty_chunk, empty_chunk, AUTH_CA); /* cacert not found or self-signed root cacert-> exit */ if (cacert == NULL || same_dn(cacert->issuer, a)) break; /* does the issuer of CA a match CA b? */ match = same_dn(cacert->issuer, b); /* we have a match and exit the loop */ if (match) break; /* go one level up in the CA chain */ a = cacert->issuer; } unlock_authcert_list("trusted_ca"); DBG(DBG_X509 | DBG_CONTROLMORE, DBG_log(" trusted_ca returning with %s", match ? "match" : "failed")); return match; }
/* * check if any crls are about to expire */ void check_crls(void) { x509crl_t *crl; lock_crl_list("check_crls"); crl = x509crls; while (crl != NULL) { deltatime_t time_left = realtimediff(crl->nextUpdate, realnow()); char buf[ASN1_BUF_LEN]; DBG(DBG_X509, { dntoa(buf, ASN1_BUF_LEN, crl->issuer); DBG_log("issuer: '%s'", buf); if (crl->authKeyID.ptr != NULL) { datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':', buf, ASN1_BUF_LEN); DBG_log("authkey: %s", buf); } DBG_log("%ld seconds left", (long)deltasecs(time_left)); }); if (deltaless(time_left, deltatimescale(2, 1, crl_check_interval))) add_crl_fetch_request(crl->issuer, crl->distributionPoints); crl = crl->next; }
/* * check if any crls are about to expire */ void check_crls(void) { #ifdef HAVE_THREADS x509crl_t *crl; time_t current_time = time(NULL); lock_crl_list("check_crls"); crl = x509crls; while (crl != NULL) { time_t time_left = crl->nextUpdate - current_time; u_char buf[ASN1_BUF_LEN]; DBG(DBG_X509, dntoa(buf, ASN1_BUF_LEN, crl->issuer); DBG_log("issuer: '%s'",buf); if (crl->authKeyID.ptr != NULL) { datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':' , buf, ASN1_BUF_LEN); DBG_log("authkey: %s", buf); } DBG_log("%ld seconds left", time_left) ) if (time_left < 2*crl_check_interval) add_crl_fetch_request(crl->issuer, crl->distributionPoints); crl = crl->next; } unlock_crl_list("check_crls"); #endif }
/* * check if an ocsp status is about to expire */ void check_ocsp(void) { ocsp_location_t *location; lock_ocsp_cache("check_ocsp"); location = ocsp_cache; while (location != NULL) { char buf[BUF_LEN]; bool first = TRUE; ocsp_certinfo_t *certinfo = location->certinfo; while (certinfo != NULL) { if (!certinfo->once) { time_t time_left = certinfo->nextUpdate - time(NULL); DBG(DBG_CONTROL, if (first) { dntoa(buf, BUF_LEN, location->issuer); DBG_log("issuer: '%s'", buf); if (location->authKeyID.ptr != NULL) { datatot(location->authKeyID.ptr, location->authKeyID.len , ':', buf, BUF_LEN); DBG_log("authkey: %s", buf); } first = FALSE; } datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len , ':', buf, BUF_LEN); DBG_log("serial: %s, %ld seconds left", buf, time_left) ) #ifdef HAVE_THREADS if (time_left < 2*crl_check_interval) add_ocsp_fetch_request(location, certinfo->serialNumber); #endif } certinfo = certinfo->next; } location = location->next; }
/* * verify if a cert hasn't been revoked by a crl */ static bool verify_by_crl(/*const*/ x509cert_t *cert, bool strict, realtime_t *until) { x509crl_t *crl; char ibuf[ASN1_BUF_LEN], cbuf[ASN1_BUF_LEN]; lock_crl_list("verify_by_crl"); crl = get_x509crl(cert->issuer, cert->authKeySerialNumber, cert->authKeyID); dntoa(ibuf, ASN1_BUF_LEN, cert->issuer); if (crl == NULL) { unlock_crl_list("verify_by_crl"); libreswan_log("no crl from issuer \"%s\" found (strict=%s)", ibuf, strict ? "yes" : "no"); #if defined(LIBCURL) || defined(LDAP_VER) if (cert->crlDistributionPoints != NULL) { add_crl_fetch_request(cert->issuer, cert->crlDistributionPoints); wake_fetch_thread("verify_by_crl"); } #endif if (strict) return FALSE; } else { x509cert_t *issuer_cert; bool valid; DBG(DBG_X509, DBG_log("issuer crl \"%s\" found", ibuf)); #if defined(LIBCURL) || defined(LDAP_VER) add_distribution_points(cert->crlDistributionPoints, &crl->distributionPoints); #endif lock_authcert_list("verify_by_crl"); issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber, crl->authKeyID, AUTH_CA); dntoa(cbuf, ASN1_BUF_LEN, crl->issuer); valid = check_signature(crl->tbsCertList, crl->signature, crl->algorithm, issuer_cert); unlock_authcert_list("verify_by_crl"); if (valid) { bool revoked_crl, expired_crl; DBG(DBG_X509, DBG_log("valid crl signature on \"%s\"", cbuf)); /* with strict crl policy the public key must have the same * lifetime as the crl */ if (strict && realbefore(crl->nextUpdate, *until)) *until = crl->nextUpdate; /* has the certificate been revoked? */ revoked_crl = x509_check_revocation(crl, cert->serialNumber); /* is the crl still valid? */ expired_crl = realbefore(crl->nextUpdate, realnow()); unlock_crl_list("verify_by_crl"); if (expired_crl) { char tbuf[REALTIMETOA_BUF]; libreswan_log( "crl update for \"%s\" is overdue since %s", cbuf, realtimetoa(crl->nextUpdate, TRUE, tbuf, sizeof(tbuf))); #if defined(LIBCURL) || defined(LDAP_VER) /* try to fetch a crl update */ if (cert->crlDistributionPoints != NULL) { add_crl_fetch_request(cert->issuer, cert->crlDistributionPoints); wake_fetch_thread("verify_by_crl"); } #endif } else { DBG(DBG_X509, DBG_log("crl is \"%s\" valid", cbuf)); } if (revoked_crl || (strict && expired_crl)) { /* remove any cached public keys */ remove_x509_public_key(cert); return FALSE; } } else { unlock_crl_list("verify_by_crl"); libreswan_log("invalid crl signature on \"%s\"", cbuf); if (strict) return FALSE; } } return TRUE; }
int idtoa(const struct id *id, char *dst, size_t dstlen) { int n; id = resolve_myid(id); switch (id->kind) { case ID_MYID: n = snprintf(dst, dstlen, "%s", "%myid"); break; case ID_FROMCERT: n = snprintf(dst, dstlen, "%s", "%fromcert"); break; case ID_NONE: n = snprintf(dst, dstlen, "%s", "(none)"); break; case ID_IPV4_ADDR: case ID_IPV6_ADDR: if(isanyaddr(&id->ip_addr)) { dst[0]='\0'; strncat(dst, "%any", dstlen); n = strlen(dst); } else { n = (int)addrtot(&id->ip_addr, 0, dst, dstlen) - 1; } break; case ID_FQDN: n = snprintf(dst, dstlen, "@%.*s", (int)id->name.len, id->name.ptr); break; case ID_USER_FQDN: n = snprintf(dst, dstlen, "%.*s", (int)id->name.len, id->name.ptr); break; case ID_DER_ASN1_DN: n = dntoa(dst, dstlen, id->name); break; case ID_KEY_ID: passert(dstlen > 4); dst[0]='@'; dst[1]='#'; dstlen-=2; dst+=2; n = keyidtoa(dst, dstlen, id->name); n+= 2; break; default: n = snprintf(dst, dstlen, "unknown id kind %d", id->kind); break; } /* "Sanitize" string so that log isn't endangered: * replace unprintable characters with '?'. */ if (n > 0) { for ( ; *dst != '\0'; dst++) if (!isprint(*dst)) *dst = '?'; } return n; }
static int dntoasi(char *dst, size_t dstlen, SECItem si) { chunk_t ch = same_secitem_as_chunk(si); return dntoa(dst, dstlen, ch); }
/* x509.c SEAM */ static void list_x509cert_chain(const char *caption, x509cert_t* cert, u_char auth_flags , bool utc) { bool first = TRUE; time_t tnow; /* determine the current time */ time(&tnow); while (cert != NULL) { if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags)) { unsigned keysize; char keyid[KEYID_BUF]; char buf[ASN1_BUF_LEN]; char tbuf[TIMETOA_BUF]; cert_t c; c.type = CERT_X509_SIGNATURE; c.u.x509 = cert; if (first) { DBG_log( " "); DBG_log( "List of X.509 %s Certificates:", caption); DBG_log( " "); first = FALSE; } DBG_log( "NOW, count: %d", cert->count); dntoa(buf, ASN1_BUF_LEN, cert->subject); DBG_log( " subject: '%s'", buf); dntoa(buf, ASN1_BUF_LEN, cert->issuer); DBG_log( " issuer: '%s'", buf); datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':' , buf, ASN1_BUF_LEN); DBG_log( " serial: %s", buf); form_keyid(cert->publicExponent, cert->modulus, keyid, &keysize); DBG_log( " pubkey: %4d RSA Key %s" , 8*keysize, keyid); DBG_log( " validity: not before %s %s", timetoa(&cert->notBefore, utc, tbuf, sizeof(tbuf)), (cert->notBefore < tnow)?"ok":"fatal (not valid yet)"); DBG_log( " not after %s %s", timetoa(&cert->notAfter, utc, tbuf, sizeof(tbuf)), check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE)); if (cert->subjectKeyID.ptr != NULL) { datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':' , buf, ASN1_BUF_LEN); DBG_log( " subjkey: %s", buf); } if (cert->authKeyID.ptr != NULL) { datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' , buf, ASN1_BUF_LEN); DBG_log( " authkey: %s", buf); } if (cert->authKeySerialNumber.ptr != NULL) { datatot(cert->authKeySerialNumber.ptr, cert->authKeySerialNumber.len , ':', buf, ASN1_BUF_LEN); DBG_log( " aserial: %s", buf); } } cert = cert->next; } }
/* establish trust into a candidate authcert by going up the trust chain. * validity and revocation status are not checked. */ bool trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) { int pathlen; lock_authcert_list("trust_authcert_candidate"); for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) { const x509cert_t *authcert = NULL; DBG(DBG_CONTROL, char buf[ASN1_BUF_LEN]; dntoa(buf, ASN1_BUF_LEN, cert->subject); DBG_log("subject: '%s'",buf); dntoa(buf, ASN1_BUF_LEN, cert->issuer); DBG_log("issuer: '%s'",buf); if (cert->authKeyID.ptr != NULL) { datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' , buf, ASN1_BUF_LEN); DBG_log("authkey: %s", buf); } ); /* search in alternative chain first */ authcert = get_alt_cacert(cert->issuer, cert->authKeySerialNumber , cert->authKeyID, alt_chain); if (authcert != NULL) { DBG(DBG_CONTROL, DBG_log("issuer cacert found in alternative chain") ) } else { /* search in trusted chain */ authcert = get_authcert(cert->issuer, cert->authKeySerialNumber , cert->authKeyID, AUTH_CA); if (authcert != NULL) { DBG(DBG_CONTROL, DBG_log("issuer cacert found") ) } else { plog("issuer cacert not found"); unlock_authcert_list("trust_authcert_candidate"); return FALSE; } } if (!check_signature(cert->tbsCertificate, cert->signature, cert->algorithm, authcert)) { plog("invalid certificate signature"); unlock_authcert_list("trust_authcert_candidate"); return FALSE; } DBG(DBG_CONTROL, DBG_log("valid certificate signature") ) /* check if cert is a self-signed root ca */ if (pathlen > 0 && same_dn(cert->issuer, cert->subject)) { DBG(DBG_CONTROL, DBG_log("reached self-signed root ca") ) unlock_authcert_list("trust_authcert_candidate"); return TRUE; } /* go up one step in the trust chain */ cert = authcert; }
static char *dntoasi(dntoasi_buf_t *dst, SECItem si) { dntoa(dst->buf, sizeof(dst->buf), same_secitem_as_chunk(si)); return dst->buf; }