📄 x509.c
字号:
while (*pp != NULL) { x509cert_t *cert = *pp; if (cert->isCA) { *pp = cert->next; /* we don't accept self-signed CA certs */ if (same_dn(cert->issuer, cert->subject)) { openswan_log("self-signed cacert rejected"); free_x509cert(cert); } else { /* insertion into temporary chain of candidate CA certs */ cert->next = cacerts; cacerts = cert; } } else pp = &cert->next; } /* now verify the candidate CA certs */ while (cacerts != NULL) { x509cert_t *cert = cacerts; cacerts = cacerts->next; if (trust_authcert_candidate(cert, cacerts)) { add_authcert(cert, AUTH_CA); } else { plog("intermediate cacert rejected"); free_x509cert(cert); } } /* now verify the end certificates */ pp = firstcert; while (*pp != NULL) { time_t valid_until; x509cert_t *cert = *pp; if (verify_x509cert(cert, strict, &valid_until)) { DBG(DBG_X509 | DBG_PARSING, DBG_log("public key validated") ) add_x509_public_key(cert, valid_until, DAL_SIGNED); } else { openswan_log("X.509 certificate rejected"); } *pp = cert->next; free_x509cert(cert); }}/* * compute a digest over a binary blob */boolcompute_digest(chunk_t tbs, int alg, chunk_t *digest){ switch (alg) { case OID_MD2: case OID_MD2_WITH_RSA: { MD2_CTX context; MD2Init(&context); MD2Update(&context, tbs.ptr, tbs.len); MD2Final(digest->ptr, &context); digest->len = MD2_DIGEST_SIZE; return TRUE; } case OID_MD5: case OID_MD5_WITH_RSA: { MD5_CTX context; osMD5Init(&context); osMD5Update(&context, tbs.ptr, tbs.len); osMD5Final(digest->ptr, &context); digest->len = MD5_DIGEST_SIZE; return TRUE; } case OID_SHA1: case OID_SHA1_WITH_RSA: case OID_SHA1_WITH_RSA_OIW: { SHA1_CTX context; SHA1Init(&context); SHA1Update(&context, tbs.ptr, tbs.len); SHA1Final(digest->ptr, &context); digest->len = SHA1_DIGEST_SIZE; return TRUE; } default: digest->len = 0; return FALSE; }}/* * decrypts an RSA signature using the issuer's certificate */static booldecrypt_sig(chunk_t sig, int alg, const x509cert_t *issuer_cert, chunk_t *digest){ switch (alg) { chunk_t decrypted; case OID_RSA_ENCRYPTION: case OID_MD2_WITH_RSA: case OID_MD5_WITH_RSA: case OID_SHA1_WITH_RSA: case OID_SHA1_WITH_RSA_OIW: case OID_SHA256_WITH_RSA: case OID_SHA384_WITH_RSA: case OID_SHA512_WITH_RSA: { mpz_t s; mpz_t e; mpz_t n; n_to_mpz(s, sig.ptr, sig.len); n_to_mpz(e, issuer_cert->publicExponent.ptr, issuer_cert->publicExponent.len); n_to_mpz(n, issuer_cert->modulus.ptr, issuer_cert->modulus.len); /* decrypt the signature s = s^e mod n */ mpz_powm(s, s, e, n); /* convert back to bytes */ decrypted = mpz_to_n(s, issuer_cert->modulus.len); DBG(DBG_PARSING, DBG_dump_chunk(" decrypted signature: ", decrypted) ) /* copy the least significant bits of decrypted signature * into the digest string */ memcpy(digest->ptr, decrypted.ptr + decrypted.len - digest->len, digest->len); /* free memory */ pfree(decrypted.ptr); mpz_clear(s); mpz_clear(e); mpz_clear(n); return TRUE; } default: digest->len = 0; return FALSE; }}/* * Check if a signature over binary blob is genuine */boolcheck_signature(chunk_t tbs, chunk_t sig, int algorithm, const x509cert_t *issuer_cert){ u_char digest_buf[MAX_DIGEST_LEN]; u_char decrypted_buf[MAX_DIGEST_LEN]; chunk_t digest = {digest_buf, MAX_DIGEST_LEN}; chunk_t decrypted = {decrypted_buf, MAX_DIGEST_LEN}; if (algorithm != OID_UNKNOWN) { DBG(DBG_X509 | DBG_PARSING, DBG_log("signature algorithm: '%s'",oid_names[algorithm].name); ) } else { DBG(DBG_X509 | DBG_PARSING, DBG_log("unknown signature algorithm"); ) } if (!compute_digest(tbs, algorithm, &digest)) { openswan_log(" digest algorithm not supported"); return FALSE; } DBG(DBG_PARSING, DBG_dump_chunk(" digest:", digest) ) decrypted.len = digest.len; /* we want the same digest length */ if (!decrypt_sig(sig, algorithm, issuer_cert, &decrypted)) { openswan_log(" decryption algorithm not supported"); return FALSE; } /* check if digests are equal */ return !memcmp(decrypted.ptr, digest.ptr, digest.len);}/* * Insert X.509 CRL into chained list */boolinsert_crl(chunk_t blob, chunk_t crl_uri){ x509crl_t *crl = alloc_thing(x509crl_t, "x509crl"); *crl = empty_x509crl; if (parse_x509crl(blob, 0, crl)) { x509cert_t *issuer_cert; x509crl_t *oldcrl; bool valid_sig; generalName_t *gn; /* add distribution point */ gn = alloc_thing(generalName_t, "generalName"); gn->kind = GN_URI; gn->name = crl_uri; gn->next = crl->distributionPoints; crl->distributionPoints = gn; lock_authcert_list("insert_crl"); /* get the issuer cacert */ issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber, crl->authKeyID, AUTH_CA); if (issuer_cert == NULL) { char distpoint[PATH_MAX]; strncpy(distpoint, crl->distributionPoints->name.ptr, (crl->distributionPoints->name.len < PATH_MAX ? crl->distributionPoints->name.len : PATH_MAX)); openswan_log("crl issuer cacert not found for (%s)", distpoint);; free_crl(crl); unlock_authcert_list("insert_crl"); return FALSE; } DBG(DBG_X509, DBG_log("crl issuer cacert found") ) /* check the issuer's signature of the crl */ valid_sig = check_signature(crl->tbsCertList, crl->signature , crl->algorithm, issuer_cert); unlock_authcert_list("insert_crl"); if (!valid_sig) { free_crl(crl); return FALSE; } DBG(DBG_X509, DBG_log("crl signature is valid") ) lock_crl_list("insert_crl"); oldcrl = get_x509crl(crl->issuer, crl->authKeySerialNumber , crl->authKeyID); if (oldcrl != NULL) { if (crl->thisUpdate > oldcrl->thisUpdate) {#ifdef HAVE_THREADS /* keep any known CRL distribution points */ add_distribution_points(oldcrl->distributionPoints , &crl->distributionPoints);#endif /* now delete the old CRL */ free_first_crl(); DBG(DBG_X509, DBG_log("thisUpdate is newer - existing crl deleted") ) } else { unlock_crl_list("insert_crls"); DBG(DBG_X509, DBG_log("thisUpdate is not newer - existing crl not replaced"); ) free_crl(crl); return oldcrl->nextUpdate - time(NULL) > 2*crl_check_interval; } } /* insert new CRL */ crl->next = x509crls; x509crls = crl; unlock_crl_list("insert_crl"); /* is the fetched crl valid? */ return crl->nextUpdate - time(NULL) > 2*crl_check_interval; } else { openswan_log(" error in X.509 crl"); free_crl(crl); return FALSE; }} /* * Loads CRLs */voidload_crls(void){ struct dirent **filelist; u_char buf[BUF_LEN]; u_char *save_dir; int n; /* change directory to specified path */ save_dir = getcwd(buf, BUF_LEN); if (chdir(CRL_PATH)) { openswan_log("Could not change to directory '%s'", CRL_PATH); } else { openswan_log("Changing to directory '%s'", CRL_PATH); n = scandir(CRL_PATH, &filelist, file_select, alphasort); if (n <= 0) openswan_log(" Warning: empty directory"); else { while (n--) { bool pgp = FALSE; chunk_t blob = empty_chunk; char *filename = filelist[n]->d_name; if (load_coded_file(filename, NULL, "crl", &blob, &pgp)) { chunk_t crl_uri; crl_uri.len = 8 + strlen(CRL_PATH) + strlen(filename); crl_uri.ptr = alloc_bytes(crl_uri.len + 1, "crl uri"); /* build CRL file URI */ snprintf(crl_uri.ptr, crl_uri.len +1, "file://%s/%s", CRL_PATH, filename); insert_crl(blob, crl_uri); } free(filelist[n]); } free(filelist); } } /* restore directory path */ chdir(save_dir);}/* * extracts the basicConstraints extension */static boolparse_basicConstraints(chunk_t blob, int level0){ asn1_ctx_t ctx; chunk_t object; u_int level; int objectID = 0; bool isCA = FALSE; asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); while (objectID < BASIC_CONSTRAINTS_ROOF) { if (!extract_object(basicConstraintsObjects, &objectID, &object,&level, &ctx)) break; if (objectID == BASIC_CONSTRAINTS_CA) { isCA = object.len && *object.ptr; DBG(DBG_PARSING, DBG_log(" %s",(isCA)?"TRUE":"FALSE"); ) } objectID++; } return isCA;}/* * Converts a X.500 generalName into an ID */voidgntoid(struct id *id, const generalName_t *gn){ switch(gn->kind) { case GN_DNS_NAME: /* ID type: ID_FQDN */ id->kind = ID_FQDN; id->name = gn->name; break; case GN_IP_ADDRESS: /* ID type: ID_IPV4_ADDR */ { const struct af_info *afi = &af_inet4_info; err_t ugh = NULL; id->kind = afi->id_addr; ugh = initaddr(gn->name.ptr, gn->name.len, afi->af, &id->ip_addr); } break; case GN_RFC822_NAME: /* ID type: ID_USER_FQDN */ id->kind = ID_USER_FQDN; id->name = gn->name; break; default: id->kind = ID_NONE; id->name = empty_chunk; }}/* * extracts a generalName */static generalName_t*parse_generalName(chunk_t blob, int level0){ u_char buf[BUF_LEN]; asn1_ctx_t ctx; chunk_t object; int objectID = 0; u_int level; asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); while (objectID < GN_OBJ_ROOF) { bool valid_gn = FALSE; if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx)) return NULL; switch (objectID) { case GN_OBJ_RFC822_NAME: case GN_OBJ_DNS_NAME: case GN_OBJ_URI: DBG(DBG_PARSING, DBG_log(" '%.*s'", (int)object.len, object.ptr); ) valid_gn = TRUE; break; case GN_OBJ_DIRECTORY_NAME: DBG(DBG_PARSING, dntoa(buf, BUF_LEN, object); DBG_log(" '%s'", buf) ) valid_gn = TRUE; break; case GN_OBJ_IP_ADDRESS: DBG(DBG_PARSING, DBG_log(" '%d.%d.%d.%d'", *object.ptr, *(object.ptr+1), *(object.ptr+2), *(object.ptr+3)); ) valid_gn = TRUE; break; case GN_OBJ_OTHER_NAME: case GN_OBJ_X400_ADDRESS: case GN_OBJ_EDI_PARTY_NAME: case GN_OBJ_REGISTERED_ID: break; default: break; } if (valid_gn) { generalName_t *gn = alloc_thing(generalName_t, "generalName"); gn->kind = (objectID - GN_OBJ_OTHER_NAME) / 2; gn->name = object; gn->next = FALSE; return gn; } objectID++; } return NULL;}/* * extracts one or several GNs and puts them into a chained list
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -