void x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int depth, X509 *x509) { X509_NAME *x509_name = X509_get_subject_name (x509); const char nullc = '\0'; int i; while (xt) { if (depth == 0 || (xt->flags & XT_FULL_CHAIN)) { i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1); if (i >= 0) { X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i); if (ent) { ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent); unsigned char *buf; buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ if (ASN1_STRING_to_UTF8 (&buf, val) > 0) { do_setenv_x509(es, xt->name, (char *)buf, depth); OPENSSL_free (buf); } } } else { i = X509_get_ext_by_NID(x509, xt->nid, -1); if (i >= 0) { X509_EXTENSION *ext = X509_get_ext(x509, i); if (ext) { BIO *bio = BIO_new(BIO_s_mem()); if (bio) { if (X509V3_EXT_print(bio, ext, 0, 0)) { if (BIO_write(bio, &nullc, 1) == 1) { char *str; BIO_get_mem_data(bio, &str); do_setenv_x509(es, xt->name, str, depth); } } BIO_free(bio); } } } } } xt = xt->next; } }
/* * Modifies a certificate by deleting extensions and copying the issuer and * AKID from the presigner certificate, if necessary. * Returns 1 on success, 0 otherwise. */ __owur static int ct_x509_cert_fixup(X509 *cert, X509 *presigner) { int preidx, certidx; int pre_akid_ext_is_dup, cert_akid_ext_is_dup; if (presigner == NULL) return 1; preidx = ct_x509_get_ext(presigner, NID_authority_key_identifier, &pre_akid_ext_is_dup); certidx = ct_x509_get_ext(cert, NID_authority_key_identifier, &cert_akid_ext_is_dup); /* An error occurred whilst searching for the extension */ if (preidx < -1 || certidx < -1) return 0; /* Invalid certificate if they contain duplicate extensions */ if (pre_akid_ext_is_dup || cert_akid_ext_is_dup) return 0; /* AKID must be present in both certificate or absent in both */ if (preidx >= 0 && certidx == -1) return 0; if (preidx == -1 && certidx >= 0) return 0; /* Copy issuer name */ if (!X509_set_issuer_name(cert, X509_get_issuer_name(presigner))) return 0; if (preidx != -1) { /* Retrieve and copy AKID encoding */ X509_EXTENSION *preext = X509_get_ext(presigner, preidx); X509_EXTENSION *certext = X509_get_ext(cert, certidx); ASN1_OCTET_STRING *preextdata; /* Should never happen */ if (preext == NULL || certext == NULL) return 0; preextdata = X509_EXTENSION_get_data(preext); if (preextdata == NULL || !X509_EXTENSION_set_data(certext, preextdata)) return 0; } return 1; }
int subjectaltnameregexp(X509 *cert, int type, const char *exact, const regex_t *regex) { int loc, i, l, n, r = 0; char *s, *v; X509_EXTENSION *ex; STACK_OF(GENERAL_NAME) *alt; GENERAL_NAME *gn; debug(DBG_DBG, "subjectaltnameregexp"); loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1); if (loc < 0) return r; ex = X509_get_ext(cert, loc); alt = X509V3_EXT_d2i(ex); if (!alt) return r; n = sk_GENERAL_NAME_num(alt); for (i = 0; i < n; i++) { gn = sk_GENERAL_NAME_value(alt, i); if (gn->type != type) continue; r = -1; v = (char *)ASN1_STRING_data(gn->d.ia5); l = ASN1_STRING_length(gn->d.ia5); if (l <= 0) continue; #ifdef DEBUG printfchars(NULL, gn->type == GEN_DNS ? "dns" : "uri", NULL, v, l); #endif if (exact) { if (memcmp(v, exact, l)) continue; } else { s = stringcopy((char *)v, l); if (!s) { debug(DBG_ERR, "malloc failed"); continue; } if (regexec(regex, s, 0, NULL, 0)) { free(s); continue; } free(s); } r = 1; break; } GENERAL_NAMES_free(alt); return r; }
/* * Copy a X509v3 extension from one certificate to another. * If the extension is not present in the original certificate, * the extension will not be added to the destination certificate. * Returns 1 if ext was copied, 0 if not present in origcrt, -1 on error. */ int ssl_x509_v3ext_copy_by_nid(X509 *crt, X509 *origcrt, int nid) { X509_EXTENSION *ext; int pos; pos = X509_get_ext_by_NID(origcrt, nid, -1); if (pos == -1) return 0; ext = X509_get_ext(origcrt, pos); if (!ext) return -1; if (X509_add_ext(crt, ext, -1) != 1) return -1; return 1; }
IoObject *IoCertificate_extensions(IoCertificate *self, IoObject *locals, IoMessage *m) { IoObject *map = IoObject_new(IoObject_state(self)); int i; for(i = 0; i < X509_get_ext_count(X509(self)); i++) { IoObject *ioext = IoObject_new(IoObject_state(self)); X509_EXTENSION *ext = X509_get_ext(X509(self), i); const char *key = (const char *)OBJ_nid2ln(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); const char *value = (const char *)ASN1_STRING_data(X509_EXTENSION_get_data(ext)); int isCritical = X509_EXTENSION_get_critical(ext); IoObject_setSlot_to_(ioext, IOSYMBOL("value"), IoSeq_newWithCString_(IoObject_state(self), value)); IoObject_setSlot_to_(ioext, IOSYMBOL("isCritical"), IONUMBER(isCritical)); IoObject_setSlot_to_(map, IOSYMBOL(key), ioext); } return map; }
int verify_cert_hostname(X509 *cert, char *hostname) { int extcount, i, j, ok = 0; char name[256]; X509_NAME *subj; const char *extstr; unsigned char *data; X509_EXTENSION *ext; X509V3_EXT_METHOD *meth; int l = strlen(hostname); char hostname_end[256]; strncpy(hostname_end, hostname, sizeof(hostname_end)); hostname_end[l+1]=hostname[l]; hostname_end[l]='.'; //update me [WIP] - feel free to edit if ((extcount = X509_get_ext_count(cert)) > 0) { for (i = 0; !ok && i < extcount; i++) { ext = X509_get_ext(cert, i); extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); if (!strcasecmp(extstr, "subjectAltName")) { if (!(meth = X509V3_EXT_get(ext))) break; data = ext->value->data; int i; if (/*i = */strstr(data, hostname) != NULL){ //printf("dada: %d\n", i); if (strstr(data, hostname_end) == NULL) { ok = 1; break; } } } } } if (!ok && (subj = X509_get_subject_name(cert)) && X509_NAME_get_text_by_NID(subj, NID_commonName, name, sizeof(name)) > 0) { name[sizeof(name) - 1] = '\0'; if (!strcasecmp(name, hostname)) { ok = 1; } } return ok; }
PKI_X509_EXTENSION_STACK *PKI_X509_CERT_get_extensions(const PKI_X509_CERT *x) { PKI_X509_EXTENSION_STACK *ret = NULL; int i = 0; int ext_count = 0; if (!x) return NULL; if ((ext_count = X509_get_ext_count (x->value)) <= 0 ) return NULL; for ( i=0; i < ext_count; i++ ) { LIBPKI_X509_EXTENSION *ext = NULL; // PKI_X509_EXTENSION_VALUE *ext = NULL; PKI_X509_EXTENSION *pki_ext = NULL; if((ext = X509_get_ext ( x->value, i )) == NULL ) { continue; } if((pki_ext = PKI_X509_EXTENSION_new()) == NULL ) { PKI_log_err ( "Memory Allocation"); continue; } if( ext->object == NULL ) { PKI_X509_EXTENSION_free ( pki_ext ); continue; } pki_ext->oid = PKI_OID_dup ( ext->object ); pki_ext->critical = ext->critical; if((pki_ext->value = X509V3_EXT_d2i ( ext )) == NULL ) { PKI_log_debug( "Extension %d -- not parsable", i); PKI_X509_EXTENSION_free ( pki_ext ); continue; } } return ret; }
/* Returns a pointer to the subjectAltName information of X509 certificate. */ int x509_cert_subjectaltname(X509 *scert, u_int8_t **altname, u_int32_t *len) { X509_EXTENSION *subjectaltname; u_int8_t *sandata; int extpos, santype, sanlen; extpos = X509_get_ext_by_NID(scert, NID_subject_alt_name, -1); if (extpos == -1) { log_print("x509_cert_subjectaltname: " "certificate does not contain subjectAltName"); return 0; } subjectaltname = X509_get_ext(scert, extpos); if (!subjectaltname || !subjectaltname->value || !subjectaltname->value->data || subjectaltname->value->length < 4) { log_print("x509_cert_subjectaltname: invalid " "subjectaltname extension"); return 0; } /* SSL does not handle unknown ASN stuff well, do it by hand. */ sandata = subjectaltname->value->data; santype = sandata[2] & 0x3f; sanlen = sandata[3]; sandata += 4; /* * The test here used to be !=, but some certificates can include * extra stuff in subjectAltName, so we will just take the first * salen bytes, and not worry about what follows. */ if (sanlen + 4 > subjectaltname->value->length) { log_print("x509_cert_subjectaltname: subjectaltname invalid " "length"); return 0; } *len = sanlen; *altname = sandata; return santype; }
PKI_X509_EXTENSION_STACK *PKI_X509_EXTENSION_get_list ( void *x, PKI_X509_DATA type ) { PKI_X509_EXTENSION_STACK *ret = NULL; int i = 0; int ext_count = 0; if (!x) return NULL; if ((ext_count = X509_get_ext_count (x)) <= 0 ) return NULL; if(( ret = PKI_STACK_X509_EXTENSION_new()) == NULL ) return NULL; for ( i=0; i < ext_count; i++ ) { PKI_X509_EXTENSION_VALUE *ext = NULL; PKI_X509_EXTENSION *pki_ext = NULL; if((ext = X509_get_ext ( x, i )) == NULL ) { continue; } if((pki_ext = PKI_X509_EXTENSION_new()) == NULL ) { PKI_log_err ( "Memory Allocation"); continue; } pki_ext->oid = ext->object; pki_ext->critical = ext->critical; if((pki_ext->value = X509V3_EXT_d2i ( ext )) == NULL ) { PKI_log_debug( "Extension %d -- not parsable", i); PKI_X509_EXTENSION_free ( pki_ext ); continue; } PKI_STACK_X509_EXTENSION_push ( ret, pki_ext ); } return ret; }
static int verify_cert_hostname(X509 *cert, char *hostname) { int extcount, i, j, ok = 0; char name[256]; X509_NAME *subj; const char *extstr; CONF_VALUE *nval; const unsigned char *data; X509_EXTENSION *ext; X509V3_EXT_METHOD *meth; STACK_OF(CONF_VALUE) *val; if ((extcount = X509_get_ext_count(cert)) > 0) { for (i = 0; !ok && i < extcount; i++) { ext = X509_get_ext(cert, i); extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); if (!strcasecmp(extstr, "subjectAltName")) { if (!(meth = (X509V3_EXT_METHOD *)X509V3_EXT_get(ext))) break; data = ext->value->data; val = meth->i2v(meth, meth->d2i(0, &data, ext->value->length), 0); for (j = 0; j < sk_CONF_VALUE_num(val); j++) { nval = sk_CONF_VALUE_value(val, j); if (!strcasecmp(nval->name, "DNS") && !strcasecmp(nval->value, hostname)) { ok = 1; break; } } } } } if (!ok && (subj = X509_get_subject_name(cert)) && X509_NAME_get_text_by_NID(subj, NID_commonName, name, sizeof(name)) > 0) { name[sizeof(name) - 1] = '\0'; if (!strcasecmp(name, hostname)) ok = 1; } return ok; }
/* Match a hostname against the contents of a dNSName field of the subjectAltName extension, if present. This is the preferred place for a certificate to store its domain name, as opposed to in the commonName field. It has the advantage that multiple names can be stored, so that one certificate can match both "example.com" and "www.example.com". If num_checked is not NULL, the number of dNSName fields that were checked before returning will be stored in it. This is so you can distinguish between the check failing because there were names but none matched, or because there were no names to match. */ static int cert_match_dnsname(X509 *cert, const char *hostname, unsigned int *num_checked) { X509_EXTENSION *ext; STACK_OF(GENERAL_NAME) *gen_names; const X509V3_EXT_METHOD *method; unsigned char *data; int i; if (num_checked != NULL) *num_checked = 0; i = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1); if (i < 0) return 0; /* If there's more than one subjectAltName extension, forget it. */ if (X509_get_ext_by_NID(cert, NID_subject_alt_name, i) >= 0) return 0; ext = X509_get_ext(cert, i); /* See the function X509V3_EXT_print in the OpenSSL source for this method of getting a string value from an extension. */ method = X509V3_EXT_get(ext); if (method == NULL) return 0; /* We must copy this address into a temporary variable because ASN1_item_d2i increments it. We don't want it to corrupt ext->value->data. */ data = ext->value->data; /* Here we rely on the fact that the internal representation (the "i" in "i2d") for NID_subject_alt_name is STACK_OF(GENERAL_NAME). Converting it to a stack of CONF_VALUE with a i2v method is not satisfactory, because a CONF_VALUE doesn't contain the length of the value so you can't know the presence of null bytes. */ #if (OPENSSL_VERSION_NUMBER > 0x00907000L) if (method->it != NULL) { gen_names = (STACK_OF(GENERAL_NAME) *) ASN1_item_d2i(NULL, (const unsigned char **) &data, ext->value->length, ASN1_ITEM_ptr(method->it)); } else {
// returns NULL if cert doesn't contain the extension, the commitment C value otherwise BIGNUM *getCommitmentValueFromCert(char *cert_filename) { X509 *cert; FILE *fp; if (!(fp = fopen(cert_filename, "r"))) critical_error("Error reading client certificate file"); if (!(cert = PEM_read_X509(fp, NULL, NULL, NULL))) critical_error("Error reading client certificate in file"); fclose(fp); BIGNUM *toret = NULL; // enable the extension handling (retrieve/print as string) int nid = _commitmentExt_start(); // try to locate extension int extpos = X509_get_ext_by_NID(cert, nid, -1); if (extpos!=-1) { // extension found X509_EXTENSION *ext = X509_get_ext(cert, extpos); toret = _commitmentExt2BN(ext); } X509_free(cert); _commitmentExt_end(); return toret; }
static void CheckDuplicateExtensions(X509 *x509) { STACK_OF(ASN1_OBJECT) *stack = sk_ASN1_OBJECT_new(obj_cmp); for (int i = 0; i < X509_get_ext_count(x509); i++) { X509_EXTENSION *ext = X509_get_ext(x509, i); if (ext == NULL) { SetError(ERR_INVALID); continue; } ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext); if (sk_ASN1_OBJECT_find(stack, obj) >= 0) { SetError(ERR_DUPLICATE_EXTENSION); } else { sk_ASN1_OBJECT_push(stack, obj); } } sk_ASN1_OBJECT_free(stack); }
/* * Check if a x509 extension is critical */ static int is_x509_ext_critical(X509 *cert, int nid) { X509_EXTENSION *ex; ASN1_OBJECT *obj; int n, i; n = X509_get_ext_count(cert); for (i = 0; i < n; i++) { ex = X509_get_ext(cert, i); if (!ex) { continue; } obj = X509_EXTENSION_get_object(ex); if (!obj) { continue; } if (OBJ_obj2nid(obj) == nid && X509_EXTENSION_get_critical(ex)) { debug("Certificate nid %d is critical\n", nid); return 1; } } return 0; }
/* * Open the inner, decrypted PKCS7 and try to write CA/RA certificates */ int write_ca_ra(struct http_reply *s) { BIO *bio; PKCS7 *p7; STACK_OF(X509) *certs = NULL; X509 *cert = NULL; FILE *fp = NULL; int c, i, index; unsigned int n; unsigned char md[EVP_MAX_MD_SIZE]; X509_EXTENSION *ext; /* Create read-only memory bio */ bio = BIO_new_mem_buf(s->payload, s->bytes); p7 = d2i_PKCS7_bio(bio, NULL); if (p7 == NULL) { fprintf(stderr, "%s: error reading PKCS#7 data\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_FILE); } /* Get certs */ i = OBJ_obj2nid(p7->type); switch (i) { case NID_pkcs7_signed: certs = p7->d.sign->cert; break; default: printf("%s: wrong PKCS#7 type\n", pname); exit (SCEP_PKISTATUS_FILE); } /* Check */ if (certs == NULL) { fprintf(stderr, "%s: cannot find certificates\n", pname); exit (SCEP_PKISTATUS_FILE); } /* Verify the chain * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ /* Find cert */ for (i = 0; i < sk_X509_num(certs); i++) { char buffer[1024]; char name[1024]; memset(buffer, 0, 1024); memset(name, 0, 1024); cert = sk_X509_value(certs, i); /* Create name */ snprintf(name, 1024, "%s-%d", c_char, i); /* Read and print certificate information */ printf("\n%s: found certificate with\n subject: %s\n", pname, X509_NAME_oneline(X509_get_subject_name(cert), buffer, sizeof(buffer))); printf(" issuer: %s\n", X509_NAME_oneline(X509_get_issuer_name(cert), buffer, sizeof(buffer))); if (!X509_digest(cert, fp_alg, md, &n)) { ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_FILE); } /* Print key usage: */ index = X509_get_ext_by_NID(cert, NID_key_usage, -1); if (index < 0) { if (v_flag) fprintf(stderr, "%s: cannot find key usage\n", pname); /* exit (SCEP_PKISTATUS_FILE); */ } else { ext = X509_get_ext(cert, index); printf(" usage: "); X509V3_EXT_print_fp(stdout, ext, 0, 0); printf("\n"); } printf(" %s fingerprint: ", OBJ_nid2sn(EVP_MD_type(fp_alg))); for (c = 0; c < (int)n; c++) { printf("%02X%c",md[c], (c + 1 == (int)n) ?'\n':':'); } /* Write PEM-formatted file: */ if (!(fp = fopen(name, "w"))) { fprintf(stderr, "%s: cannot open cert file for " "writing\n", pname); exit (SCEP_PKISTATUS_FILE); } if (v_flag) printf("%s: writing cert\n", pname); if (d_flag) PEM_write_X509(stdout, cert); if (PEM_write_X509(fp, cert) != 1) { fprintf(stderr, "%s: error while writing certificate " "file\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_FILE); } printf("%s: certificate written as %s\n", pname, name); } (void)fclose(fp); exit (SCEP_PKISTATUS_SUCCESS); }
/** * Returns type of proxy certificate. * Valid values are: * NONE * CA * EEC * GT2_PROXY * RFC_PROXY * GT2_LIMITED_PROXY * RFC_LIMITED_PROXY * GT3_PROXY * GT3_LIMITED_PROXY */ proxy_type_t verify_type_of_proxy(X509 * cert) { #ifdef __func__ const char *logstr=__func__; #else const char *logstr="verify_type_of_proxy"; #endif proxy_type_t pt = NONE; char * cert_subjectdn = NULL; char * cert_issuerdn = NULL; char * tail_str = NULL; size_t len_subject_dn; size_t len_issuer_dn; X509_EXTENSION * pci_ext = NULL; PROXYCERTINFO * pci = NULL; PROXYPOLICY * policy = NULL; ASN1_OBJECT * policy_lang = NULL; int policy_nid; int myindex = -1; int i; char s[EXT_TEXT_LEN]; X509_EXTENSION *ex; /* Is it a CA certificate */ if (verify_x509IsCA(cert)) { /* verify_log (L_DEBUG, "%s: Detected CA certificate", logstr); */ pt = CA; goto finalize; } /* Check by OID */ for (i = 0; i < X509_get_ext_count(cert); ++i) { ex = X509_get_ext(cert, i); if (X509_EXTENSION_get_object(ex)) { OBJ_obj2txt(s, EXT_TEXT_LEN, X509_EXTENSION_get_object(ex), 1); if (strcmp(s, OID_RFC_PROXY) == 0) { pt = RFC_PROXY; /* Find index of OID_RFC_PROXY */ if((myindex = X509_get_ext_by_NID(cert, OBJ_txt2nid(OID_RFC_PROXY), -1)) != -1 && (pci_ext = X509_get_ext(cert,myindex)) && X509_EXTENSION_get_critical(pci_ext)) { if((pci = X509V3_EXT_d2i(pci_ext)) == NULL) { verify_error(logstr, "Can't convert DER encoded PROXYCERTINFO extension to internal form"); goto failure; } /* Pull a certificate policy from the extension, note: * pci!=NULL since we've checked that */ if( (policy = pci->policy) == NULL) { verify_error(logstr, "Can't get policy from PROXYCERTINFO extension"); goto failure; } /* Get policy language */ if( (policy_lang = policy->policy_language) == NULL) { verify_error(logstr, "Can't get policy language from PROXYCERTINFO extension"); goto failure; } /* Lang to NID, lang's NID holds RFC Proxy type, like limited. Impersonation is the default */ policy_nid = OBJ_obj2nid(policy_lang); if(policy_nid == OBJ_txt2nid(IMPERSONATION_PROXY_OID)) { pt = RFC_PROXY; } else if(policy_nid == OBJ_txt2nid(INDEPENDENT_PROXY_OID)) { pt = RFC_PROXY; } else if(policy_nid == OBJ_txt2nid(LIMITED_PROXY_OID)) { pt = RFC_LIMITED_PROXY; } else { /* RFC_RESTRICTED_PROXY */ pt = RFC_PROXY; } if(X509_get_ext_by_NID(cert, OBJ_txt2nid(OID_RFC_PROXY), myindex) != -1) { verify_error(logstr, "Found more than one PCI extension"); goto failure; } } goto finalize; } if (strcmp(s, OID_GLOBUS_PROXY_V3) == 0) { pt = GT3_PROXY; /* Find index of OID_GT3_PROXY - Don't make it search for critical extentions... VOMS doesn't set those. */ if((myindex = X509_get_ext_by_NID(cert, OBJ_txt2nid(OID_GLOBUS_PROXY_V3), -1)) != -1 && (pci_ext = X509_get_ext(cert,myindex))) { if((pci = X509V3_EXT_d2i(pci_ext)) == NULL) { verify_error(logstr, "Can't convert DER encoded PROXYCERTINFO extension to internal form"); goto failure; } /* Pull a certificate policy from the extension. Note: pci * != NULL since we've checked that */ if( (policy = pci->policy) == NULL) { verify_error(logstr, "Can't get policy from PROXYCERTINFO extension"); goto failure; } /* Get policy language */ if( (policy_lang = policy->policy_language) == NULL) { verify_error(logstr, "Can't get policy language from PROXYCERTINFO extension"); goto failure; } /* Lang to NID, lang's NID holds RFC Proxy type, like limited. Impersonation is the default */ policy_nid = OBJ_obj2nid(policy_lang); if(policy_nid == OBJ_txt2nid(IMPERSONATION_PROXY_OID)) { pt = GT3_PROXY; } else if(policy_nid == OBJ_txt2nid(INDEPENDENT_PROXY_OID)) { pt = GT3_PROXY; } else if(policy_nid == OBJ_txt2nid(LIMITED_PROXY_OID)) { pt = GT3_LIMITED_PROXY; } else { /* GT3_RESTRICTED_PROXY */ pt = GT3_PROXY; } if(X509_get_ext_by_NID(cert, OBJ_txt2nid(OID_GLOBUS_PROXY_V3), myindex) != -1) { verify_error(logstr, "Found more than one PCI extension"); goto failure; } } goto finalize; } if (strcmp(s, OID_GLOBUS_PROXY_V2) == 0) { pt = GT3_PROXY; /* Check for GT2_PROXY tail */ if (cert_subjectdn && (strlen(cert_subjectdn) > strlen("/cn=proxy")) && (tail_str = &cert_subjectdn[strlen(cert_subjectdn) - strlen("/cn=proxy")]) && (strcasecmp(tail_str, "/cn=proxy") == 0) ) { /* verify_log (L_DEBUG, "%s: Detected GT2 proxy certificate", logstr); */ pt = GT2_PROXY; goto finalize; } /* Check for GT2_LIMITED_PROXY tail */ if (cert_subjectdn && (strlen(cert_subjectdn) > strlen("/cn=limited proxy")) && (tail_str = &cert_subjectdn[strlen(cert_subjectdn) - strlen("/cn=limited proxy")]) && (strcasecmp(tail_str, "/cn=limited proxy") == 0) ) { /* verify_log (L_DEBUG, "%s: Detected GT2 limited proxy certificate", logstr); */ pt = GT2_LIMITED_PROXY; goto finalize; } verify_error(logstr, "Detected the Globus GT2 OID in the certificate, " "but seems to have a malformed Subject DN: \"%s\"", cert_subjectdn); goto failure; } } } /* Options left: GT2_PROXY, GT2_LIMITED_PROXY, EEC */ /* Extract Subject DN - Needs free */ if (!(cert_subjectdn = X509_NAME_oneline (X509_get_subject_name (cert), NULL, 0))) { verify_error (logstr, "Error in %s: Couldn't get the subject DN from the certificate.", logstr); goto failure; } if (!(cert_issuerdn = X509_NAME_oneline (X509_get_issuer_name (cert), NULL, 0))) { verify_error (logstr, "Error in %s: Couldn't get the issuer DN from the certificate.", logstr); goto failure; } /* Check length of the DNs */ len_subject_dn = strlen(cert_subjectdn); len_issuer_dn = strlen(cert_issuerdn); /* Lower case the Subject DN */ /* for (j = 0; j < strlen(cert_subjectdn); j++) { cert_subjectdn[j] = tolower(cert_subjectdn[j]); } */ /* Proxies always has a longer subject_dn then a issuer_dn and * the issuer_dn is a substring of the subject_dn */ if ( (len_issuer_dn < len_subject_dn) && (strncmp(cert_subjectdn, cert_issuerdn, len_issuer_dn) == 0) ) { /* Check for GT2_PROXY tail */ if (cert_subjectdn && (strlen(cert_subjectdn) > strlen("/cn=proxy")) && (tail_str = &cert_subjectdn[strlen(cert_subjectdn) - strlen("/cn=proxy")]) && (strcasecmp(tail_str, "/cn=proxy") == 0) ) { /* verify_log (L_DEBUG, "%s: Detected GT2 proxy certificate", logstr); */ pt = GT2_PROXY; goto finalize; } /* Check for GT2_LIMITED_PROXY tail */ if (cert_subjectdn && (strlen(cert_subjectdn) > strlen("/cn=limited proxy")) && (tail_str = &cert_subjectdn[strlen(cert_subjectdn) - strlen("/cn=limited proxy")]) && (strcasecmp(tail_str, "/cn=limited proxy") == 0) ) { /* verify_log (L_DEBUG, "%s: Detected GT2 limited proxy certificate", logstr); */ pt = GT2_LIMITED_PROXY; goto finalize; } /* Check for RFC_PROXY, without the need for OpenSSL proxy support */ /* Method: Check if the subject_dn is long enough, grab its tail and * snip of the 10 characters. Then check if the 10 characters are * numbers. */ if (cert_subjectdn && (strlen(cert_subjectdn) > strlen("/cn=0123456789")) && (tail_str = strrchr(cert_subjectdn, '=')) && (tail_str = &tail_str[1]) && (strtol(tail_str, NULL, 10)) && (errno != ERANGE) ) { /* verify_log (L_DEBUG, "%s: Detected RFC proxy certificate", logstr); */ pt = RFC_PROXY; goto finalize; } /* Don't know the type of proxy, could be an RFC proxy with * improper/incomplete implementation in the active OpenSSL version or * a mistake in the client software */ goto failure; } /* I have no idea what else it is, so I conclude that it's an EEC */ pt = EEC; goto finalize; failure: /* On failure, or non-distinct selections of the certificate, indicate NONE */ pt = NONE; finalize: if (cert_subjectdn) free(cert_subjectdn); if (cert_issuerdn) free(cert_issuerdn); return pt; }
static Str ssl_check_cert_ident(X509 * x, char *hostname) { int i; Str ret = NULL; int match_ident = FALSE; /* * All we need to do here is check that the CN matches. * * From RFC2818 3.1 Server Identity: * If a subjectAltName extension of type dNSName is present, that MUST * be used as the identity. Otherwise, the (most specific) Common Name * field in the Subject field of the certificate MUST be used. Although * the use of the Common Name is existing practice, it is deprecated and * Certification Authorities are encouraged to use the dNSName instead. */ i = X509_get_ext_by_NID(x, NID_subject_alt_name, -1); if (i >= 0) { X509_EXTENSION *ex; STACK_OF(GENERAL_NAME) * alt; ex = X509_get_ext(x, i); alt = X509V3_EXT_d2i(ex); if (alt) { int n; GENERAL_NAME *gn; X509V3_EXT_METHOD *method; Str seen_dnsname = NULL; n = sk_GENERAL_NAME_num(alt); for (i = 0; i < n; i++) { gn = sk_GENERAL_NAME_value(alt, i); if (gn->type == GEN_DNS) { char *sn = ASN1_STRING_data(gn->d.ia5); int sl = ASN1_STRING_length(gn->d.ia5); if (!seen_dnsname) seen_dnsname = Strnew(); /* replace \0 to make full string visible to user */ if (sl != strlen(sn)) { int i; for (i = 0; i < sl; ++i) { if (!sn[i]) sn[i] = '!'; } } Strcat_m_charp(seen_dnsname, sn, " ", NULL); if (sl == strlen(sn) /* catch \0 in SAN */ && ssl_match_cert_ident(sn, sl, hostname)) break; } } method = X509V3_EXT_get(ex); sk_GENERAL_NAME_free(alt); if (i < n) /* Found a match */ match_ident = TRUE; else if (seen_dnsname) /* FIXME: gettextize? */ ret = Sprintf("Bad cert ident from %s: dNSName=%s", hostname, seen_dnsname->ptr); } } if (match_ident == FALSE && ret == NULL) { X509_NAME *xn; char buf[2048]; int slen; xn = X509_get_subject_name(x); slen = X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof(buf)); if ( slen == -1) /* FIXME: gettextize? */ ret = Strnew_charp("Unable to get common name from peer cert"); else if (slen != strlen(buf) || !ssl_match_cert_ident(buf, strlen(buf), hostname)) { /* replace \0 to make full string visible to user */ if (slen != strlen(buf)) { int i; for (i = 0; i < slen; ++i) { if (!buf[i]) buf[i] = '!'; } } /* FIXME: gettextize? */ ret = Sprintf("Bad cert ident %s from %s", buf, hostname); } else match_ident = TRUE; } return ret; }
/** Search for a hostname match in the SubjectAlternativeNames. */ uint32_t check_san (SSL *ssl, const char *hostname) { X509 *cert; int extcount, ok = 0; /* What an OpenSSL mess ... */ if (NULL == (cert = SSL_get_peer_certificate(ssl))) { die ("Getting certificate failed"); } if ((extcount = X509_get_ext_count(cert)) > 0) { int i; for (i = 0; i < extcount; ++i) { const char *extstr; X509_EXTENSION *ext; ext = X509_get_ext(cert, i); extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); if (!strcmp(extstr, "subjectAltName")) { int j; void *extvalstr; const unsigned char *tmp; STACK_OF(CONF_VALUE) *val; CONF_VALUE *nval; #if OPENSSL_VERSION_NUMBER >= 0x10000000L const #endif X509V3_EXT_METHOD *method; if (!(method = X509V3_EXT_get(ext))) { break; } tmp = ext->value->data; if (method->it) { extvalstr = ASN1_item_d2i(NULL, &tmp, ext->value->length, ASN1_ITEM_ptr(method->it)); } else { extvalstr = method->d2i(NULL, &tmp, ext->value->length); } if (!extvalstr) { break; } if (method->i2v) { val = method->i2v(method, extvalstr, NULL); for (j = 0; j < sk_CONF_VALUE_num(val); ++j) { nval = sk_CONF_VALUE_value(val, j); if ((!strcasecmp(nval->name, "DNS") && !strcasecmp(nval->value, hostname) ) || (!strcasecmp(nval->name, "iPAddress") && !strcasecmp(nval->value, hostname))) { verb ("V: subjectAltName matched: %s, type: %s", nval->value, nval->name); // We matched this; so it's safe to print ok = 1; break; } // Attempt to match subjectAltName DNS names if (!strcasecmp(nval->name, "DNS")) { ok = check_wildcard_match_rfc2595(hostname, nval->value); if (ok) { break; } } verb_debug ("V: subjectAltName found but not matched: %s, type: %s", nval->value, sanitize_string(nval->name)); } } } else { verb_debug ("V: found non subjectAltName extension"); } if (ok) { break; } } } else { verb_debug ("V: no X509_EXTENSION field(s) found"); } X509_free(cert); return ok; }
su_inline int tls_post_connection_check(tport_t *self, tls_t *tls) { X509 *cert; int extcount; int i, j, error; if (!tls) return -1; cert = SSL_get_peer_certificate(tls->con); if (!cert) { SU_DEBUG_7(("%s(%p): Peer did not provide X.509 Certificate.\n", __func__, (void *) self)); if (self->tp_accepted && tls->verify_incoming) return X509_V_ERR_CERT_UNTRUSTED; else if (!self->tp_accepted && tls->verify_outgoing) return X509_V_ERR_CERT_UNTRUSTED; else return X509_V_OK; } tls->subjects = su_strlst_create(tls->home); if (!tls->subjects) return X509_V_ERR_OUT_OF_MEM; extcount = X509_get_ext_count(cert); /* Find matching subjectAltName.DNS */ for (i = 0; i < extcount; i++) { X509_EXTENSION *ext; char const *name; #if OPENSSL_VERSION_NUMBER > 0x10000000L const X509V3_EXT_METHOD *vp; #else X509V3_EXT_METHOD *vp; #endif STACK_OF(CONF_VALUE) *values; CONF_VALUE *value; void *d2i; ext = X509_get_ext(cert, i); name = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); if (strcmp(name, "subjectAltName") != 0) continue; vp = X509V3_EXT_get(ext); if (!vp) continue; d2i = X509V3_EXT_d2i(ext); values = vp->i2v(vp, d2i, NULL); for (j = 0; j < sk_CONF_VALUE_num(values); j++) { value = sk_CONF_VALUE_value(values, j); if (strcmp(value->name, "DNS") == 0) su_strlst_dup_append(tls->subjects, value->value); if (strcmp(value->name, "IP") == 0) su_strlst_dup_append(tls->subjects, value->value); else if (strcmp(value->name, "URI") == 0) su_strlst_dup_append(tls->subjects, value->value); } } { X509_NAME *subject; char name[256]; subject = X509_get_subject_name(cert); if (subject) { if (X509_NAME_get_text_by_NID(subject, NID_commonName, name, sizeof name) > 0) { usize_t k, N = su_strlst_len(tls->subjects); name[(sizeof name) - 1] = '\0'; for (k = 0; k < N; k++) if (su_casematch(su_strlst_item(tls->subjects, k), name) == 0) break; if (k >= N) su_strlst_dup_append(tls->subjects, name); } } } X509_free(cert); error = SSL_get_verify_result(tls->con); if (cert && error == X509_V_OK) tls->x509_verified = 1; if (tport_log->log_level >= 7) { int i, len = su_strlst_len(tls->subjects); for (i=0; i < len; i++) SU_DEBUG_7(("%s(%p): Peer Certificate Subject %i: %s\n", \ __func__, (void *)self, i, su_strlst_item(tls->subjects, i))); if (i == 0) SU_DEBUG_7(("%s(%p): Peer Certificate provided no usable subjects.\n", __func__, (void *)self)); } /* Verify incoming connections */ if (self->tp_accepted) { if (!tls->verify_incoming) return X509_V_OK; if (!tls->x509_verified) return error; if (tls->verify_subj_in) { su_strlst_t const *subjects = self->tp_pri->pri_primary->tp_subjects; int i, items; items = subjects ? su_strlst_len(subjects) : 0; if (items == 0) return X509_V_OK; for (i=0; i < items; i++) { if (tport_subject_search(su_strlst_item(subjects, i), tls->subjects)) return X509_V_OK; } SU_DEBUG_3(("%s(%p): Peer Subject Mismatch (incoming connection)\n", \ __func__, (void *)self)); return X509_V_ERR_CERT_UNTRUSTED; } } /* Verify outgoing connections */ else { char const *subject = self->tp_canon; if (!tls->verify_outgoing) return X509_V_OK; if (!tls->x509_verified || !subject) return error; if (tls->verify_subj_out) { if (tport_subject_search(subject, tls->subjects)) return X509_V_OK; /* Subject match found in verified certificate chain */ SU_DEBUG_3(("%s(%p): Peer Subject Mismatch (%s)\n", \ __func__, (void *)self, subject)); return X509_V_ERR_CERT_UNTRUSTED; } } return error; }
extern "C" X509_EXTENSION* X509GetExt(X509* x, int32_t loc) { return X509_get_ext(x, loc); }
static PyObject * _get_peer_alt_names (X509 *certificate) { /* this code follows the procedure outlined in OpenSSL's crypto/x509v3/v3_prn.c:X509v3_EXT_print() function to extract the STACK_OF(GENERAL_NAME), then iterates through the stack to add the names. */ int i, j; PyObject *peer_alt_names = Py_None; PyObject *v, *t; X509_EXTENSION *ext = NULL; GENERAL_NAMES *names = NULL; GENERAL_NAME *name; X509V3_EXT_METHOD *method; BIO *biobuf = NULL; char buf[2048]; char *vptr; int len; const unsigned char *p; if (certificate == NULL) return peer_alt_names; /* get a memory buffer */ biobuf = BIO_new(BIO_s_mem()); i = 0; while ((i = X509_get_ext_by_NID( certificate, NID_subject_alt_name, i)) >= 0) { if (peer_alt_names == Py_None) { peer_alt_names = PyList_New(0); if (peer_alt_names == NULL) goto fail; } /* now decode the altName */ ext = X509_get_ext(certificate, i); if(!(method = X509V3_EXT_get(ext))) { PyErr_SetString (PySSLErrorObject, ERRSTR("No method for internalizing subjectAltName!")); goto fail; } p = ext->value->data; if (method->it) names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it))); else names = (GENERAL_NAMES*) (method->d2i(NULL, &p, ext->value->length)); for(j = 0; j < sk_GENERAL_NAME_num(names); j++) { /* get a rendering of each name in the set of names */ name = sk_GENERAL_NAME_value(names, j); if (name->type == GEN_DIRNAME) { /* we special-case DirName as a tuple of tuples of attributes */ t = PyTuple_New(2); if (t == NULL) { goto fail; } v = PyUnicode_FromString("DirName"); if (v == NULL) { Py_DECREF(t); goto fail; } PyTuple_SET_ITEM(t, 0, v); v = _create_tuple_for_X509_NAME (name->d.dirn); if (v == NULL) { Py_DECREF(t); goto fail; } PyTuple_SET_ITEM(t, 1, v); } else { /* for everything else, we use the OpenSSL print form */ (void) BIO_reset(biobuf); GENERAL_NAME_print(biobuf, name); len = BIO_gets(biobuf, buf, sizeof(buf)-1); if (len < 0) { _setSSLError(NULL, 0, __FILE__, __LINE__); goto fail; } vptr = strchr(buf, ':'); if (vptr == NULL) goto fail; t = PyTuple_New(2); if (t == NULL) goto fail; v = PyUnicode_FromStringAndSize(buf, (vptr - buf)); if (v == NULL) { Py_DECREF(t); goto fail; } PyTuple_SET_ITEM(t, 0, v); v = PyUnicode_FromStringAndSize((vptr + 1), (len - (vptr - buf + 1))); if (v == NULL) { Py_DECREF(t); goto fail; } PyTuple_SET_ITEM(t, 1, v); } /* and add that rendering to the list */ if (PyList_Append(peer_alt_names, t) < 0) { Py_DECREF(t); goto fail; } Py_DECREF(t); } } BIO_free(biobuf); if (peer_alt_names != Py_None) { v = PyList_AsTuple(peer_alt_names); Py_DECREF(peer_alt_names); return v; } else { return peer_alt_names; } fail: if (biobuf != NULL) BIO_free(biobuf); if (peer_alt_names != Py_None) { Py_XDECREF(peer_alt_names); } return NULL; }
//extention to SSL_get_verify_result int CSSLClient::PostConnectCheck(SSL *ssl, const char *pHost) { X509 *cert; X509_NAME *subj; char data[256]; int extcount; int ret = 0; do { if (!(cert = SSL_get_peer_certificate(ssl)) || !pHost) { break; } if ((extcount = X509_get_ext_count(cert)) > 0) { int i; for (i = 0; i < extcount; i++) { const char *extstr; X509_EXTENSION *ext; ext = X509_get_ext(cert, i); extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); if (!strcmp(extstr, SN_subject_alt_name)) { int j; const unsigned char *pData; STACK_OF(CONF_VALUE) *val; CONF_VALUE *nval; const X509V3_EXT_METHOD *pExtMethod; if (!(pExtMethod = X509V3_EXT_get(ext))) { break; } pData = ext->value->data; val = pExtMethod->i2v(pExtMethod, pExtMethod->d2i(NULL, &pData, ext->value->length), NULL); for (j = 0; j < sk_CONF_VALUE_num(val); j++) { nval = sk_CONF_VALUE_value(val, j); if (!strcmp(nval->name, "DNS") && !strcmp(nval->value, pHost)) { ret = 1; break; } } } if (ret) { break; } }//end of for(; extentcount; ) } if (!ret && (subj = X509_get_subject_name(cert)) && X509_NAME_get_text_by_NID(subj, NID_commonName, data, 256) > 0) { data[255] = 0; if (strcmp(data, pHost) != 0) { break; } } X509_free(cert); ret = SSL_get_verify_result(ssl); return ret; } while(0); if (cert) { X509_free(cert); } return -1; }
static int tlso_session_chkhost( LDAP *ld, tls_session *sess, const char *name_in ) { tlso_session *s = (tlso_session *)sess; int i, ret = LDAP_LOCAL_ERROR; X509 *x; const char *name; char *ptr; int ntype = IS_DNS, nlen; #ifdef LDAP_PF_INET6 struct in6_addr addr; #else struct in_addr addr; #endif if( ldap_int_hostname && ( !name_in || !strcasecmp( name_in, "localhost" ) ) ) { name = ldap_int_hostname; } else { name = name_in; } nlen = strlen(name); x = tlso_get_cert(s); if (!x) { Debug( LDAP_DEBUG_ANY, "TLS: unable to get peer certificate.\n", 0, 0, 0 ); /* If this was a fatal condition, things would have * aborted long before now. */ return LDAP_SUCCESS; } #ifdef LDAP_PF_INET6 if (inet_pton(AF_INET6, name, &addr)) { ntype = IS_IP6; } else #endif if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) { if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4; } i = X509_get_ext_by_NID(x, NID_subject_alt_name, -1); if (i >= 0) { X509_EXTENSION *ex; STACK_OF(GENERAL_NAME) *alt; ex = X509_get_ext(x, i); alt = X509V3_EXT_d2i(ex); if (alt) { int n, len2 = 0; char *domain = NULL; GENERAL_NAME *gn; if (ntype == IS_DNS) { domain = strchr(name, '.'); if (domain) { len2 = nlen - (domain-name); } } n = sk_GENERAL_NAME_num(alt); for (i=0; i<n; i++) { char *sn; int sl; gn = sk_GENERAL_NAME_value(alt, i); if (gn->type == GEN_DNS) { if (ntype != IS_DNS) continue; sn = (char *) ASN1_STRING_data(gn->d.ia5); sl = ASN1_STRING_length(gn->d.ia5); /* ignore empty */ if (sl == 0) continue; /* Is this an exact match? */ if ((nlen == sl) && !strncasecmp(name, sn, nlen)) { break; } /* Is this a wildcard match? */ if (domain && (sn[0] == '*') && (sn[1] == '.') && (len2 == sl-1) && !strncasecmp(domain, &sn[1], len2)) { break; } } else if (gn->type == GEN_IPADD) { if (ntype == IS_DNS) continue; sn = (char *) ASN1_STRING_data(gn->d.ia5); sl = ASN1_STRING_length(gn->d.ia5); #ifdef LDAP_PF_INET6 if (ntype == IS_IP6 && sl != sizeof(struct in6_addr)) { continue; } else #endif if (ntype == IS_IP4 && sl != sizeof(struct in_addr)) { continue; } if (!memcmp(sn, &addr, sl)) { break; } } } GENERAL_NAMES_free(alt); if (i < n) { /* Found a match */ ret = LDAP_SUCCESS; } } } if (ret != LDAP_SUCCESS) { X509_NAME *xn; X509_NAME_ENTRY *ne; ASN1_OBJECT *obj; ASN1_STRING *cn = NULL; int navas; /* find the last CN */ obj = OBJ_nid2obj( NID_commonName ); if ( !obj ) goto no_cn; /* should never happen */ xn = X509_get_subject_name(x); navas = X509_NAME_entry_count( xn ); for ( i=navas-1; i>=0; i-- ) { ne = X509_NAME_get_entry( xn, i ); if ( !OBJ_cmp( X509_NAME_ENTRY_get_object(ne), obj )) { cn = X509_NAME_ENTRY_get_data( ne ); break; } } if( !cn ) { no_cn: Debug( LDAP_DEBUG_ANY, "TLS: unable to get common name from peer certificate.\n", 0, 0, 0 ); ret = LDAP_CONNECT_ERROR; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: unable to get CN from peer certificate")); } else if ( cn->length == nlen && strncasecmp( name, (char *) cn->data, nlen ) == 0 ) { ret = LDAP_SUCCESS; } else if (( cn->data[0] == '*' ) && ( cn->data[1] == '.' )) { char *domain = strchr(name, '.'); if( domain ) { int dlen; dlen = nlen - (domain-name); /* Is this a wildcard match? */ if ((dlen == cn->length-1) && !strncasecmp(domain, (char *) &cn->data[1], dlen)) { ret = LDAP_SUCCESS; } } } if( ret == LDAP_LOCAL_ERROR ) { Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " "common name in certificate (%.*s).\n", name, cn->length, cn->data ); ret = LDAP_CONNECT_ERROR; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: hostname does not match CN in peer certificate")); } } X509_free(x); return ret; }
/* * Check that the common name matches the host name */ static int check_cert_chain(conn_t * conn, SSL * ssl, ruleset_t * rs) { X509 *peer; X509_NAME *xn; static char subject[1024]; int r = FALSE, extc; if (SSL_get_verify_result(ssl) != X509_V_OK) { LOG(SPOCP_ERR) traceLog(LOG_ERR,"Certificate doesn't verify"); return FALSE; } /* * Check the cert chain. The chain length is automatically checked by * OpenSSL when we set the verify depth in the ctx */ peer = SSL_get_peer_certificate(ssl); if (!peer) { LOG(SPOCP_ERR) traceLog(LOG_ERR,"No peer certificate"); return TRUE; } /* * check subjectaltname */ if ((extc = X509_get_ext_count(peer)) > 0) { int i; for (i = 0; r == FALSE && i < extc; i++) { X509_EXTENSION *ext; const char *extstr; ext = X509_get_ext(peer, i); extstr = OBJ_nid2sn(OBJ_obj2nid (X509_EXTENSION_get_object(ext))); if (strcmp(extstr, "subjectAltName") == 0) { int j; unsigned char *data; STACK_OF(CONF_VALUE) * val; CONF_VALUE *nval; X509V3_EXT_METHOD *meth; if ((meth = X509V3_EXT_get(ext)) == 0) break; data = ext->value->data; val = meth->i2v(meth, meth->d2i(NULL, &data, ext->value->length), NULL); for (j = 0; r == FALSE && i < sk_CONF_VALUE_num(val); j++) { nval = sk_CONF_VALUE_value(val, j); if (strcasecmp(nval->name, "DNS") == 0 && strcasecmp(nval->value, conn->sri. hostname)) { r = TRUE; } } } } } if (r == FALSE) { /* * Check the subject name */ xn = X509_get_subject_name(peer); X509_NAME_get_text_by_NID(xn, NID_commonName, subject, 1024); subject[1023] = '\0'; traceLog(LOG_DEBUG,"\"%s\" = \"%s\" ?", subject, conn->sri.hostname); if (strcasecmp(subject, conn->sri.hostname) == 0) { r = TRUE; } } if (r == TRUE) { conn->subjectDN = X509_NAME_oneline(X509_get_subject_name(peer), NULL, 0); conn->issuerDN = X509_NAME_oneline(X509_get_issuer_name(peer), NULL, 0); } X509_free(peer); return r; }
extern "C" X509_EXTENSION* CryptoNative_X509GetExt(X509* x, int32_t loc) { return X509_get_ext(x, loc); }
int tls_client_start( SNET *sn, char *host, int authlevel ) { X509 *peer; char buf[ 1024 ]; struct timeval tv; char *line; int ntype; struct in_addr addr; int alt_ext; if ( inet_aton( host, &addr )) { ntype = IS_IP4; } else { /* Assume the host argument is a DNS name */ ntype = IS_DNS; } if( snet_writef( sn, "STARTTLS\r\n" ) < 0 ) { perror( "snet_writef" ); return( -1 ); } if ( verbose ) printf( ">>> STARTTLS\n" ); /* Check to see if command succeeded */ tv = timeout; if (( line = snet_getline_multi( sn, logger, &tv )) == NULL ) { perror( "snet_getline_multi" ); return( -1 ); } if ( *line != '2' ) { fprintf( stderr, "%s\n", line ); return( -1 ); } /* * Begin TLS */ /* This is where the TLS start */ /* At this point the server is also staring TLS */ if ( snet_starttls( sn, ctx, 0 ) != 1 ) { fprintf( stderr, "snet_starttls: %s\n", ERR_error_string( ERR_get_error(), NULL ) ); return( -1 ); } if (( peer = SSL_get_peer_certificate( sn->sn_ssl )) == NULL ) { fprintf( stderr, "no certificate\n" ); return( -1 ); } /* This code gratiously borrowed from openldap-2.2.17, * it allows the use of aliases in the certificate. */ alt_ext = X509_get_ext_by_NID( peer, NID_subject_alt_name, -1 ); if ( alt_ext >= 0 ) { X509_EXTENSION *ex; STACK_OF( GENERAL_NAME ) *alt; ex = X509_get_ext( peer, alt_ext ); alt = X509V3_EXT_d2i( ex ); if ( alt ) { int i, n, len1 = 0, len2 = 0; char *domain = NULL; GENERAL_NAME *gn; if ( ntype == IS_DNS ) { len1 = strlen( host ); domain = strchr( host, '.' ); if ( domain ) { len2 = len1 - ( domain-host ); } } n = sk_GENERAL_NAME_num( alt ); for ( i = 0; i < n; i++ ) { char *sn; int sl; gn = sk_GENERAL_NAME_value( alt, i ); if ( gn->type == GEN_DNS ) { if ( ntype != IS_DNS ) { continue; }; sn = (char *) ASN1_STRING_data( gn->d.ia5 ); sl = ASN1_STRING_length( gn->d.ia5 ); /* ignore empty */ if ( sl == 0 ) { continue; } /* Is this an exact match? */ if (( len1 == sl ) && !strncasecmp( host, sn, len1 )) { /* Found! */ if ( verbose ) { printf( ">>> Certificate accepted: " "subjectAltName exact match %s\n", sn ); } break; } /* Is this a wildcard match? */ if ( domain && ( sn[0] == '*' ) && ( sn[1] == '.' ) && ( len2 == sl-1 ) && strncasecmp( domain, &sn[1], len2 )) { /* Found! */ if ( verbose ) { printf( ">>> Certificate accepted: subjectAltName " "wildcard %s host %s\n", sn, host ); } break; } } else if ( gn->type == GEN_IPADD ) { if ( ntype == IS_DNS ) { continue; } sn = (char *) ASN1_STRING_data( gn->d.ia5 ); sl = ASN1_STRING_length( gn->d.ia5 ); if ( ntype == IS_IP4 && sl != sizeof( struct in_addr )) { continue; } if ( !memcmp( sn, &addr, sl )) { /* Found! */ if ( verbose ) { printf( ">>> Certificate accepted: subjectAltName " "address %s\n", host ); } break; } } } GENERAL_NAMES_free( alt ); if ( i < n ) { /* Found a match */ X509_free( peer ); return 0; } } } X509_NAME_get_text_by_NID( X509_get_subject_name( peer ), NID_commonName, buf, sizeof( buf )); X509_free( peer ); if ( strcmp( buf, host )) { fprintf( stderr, "Server's name doesn't match supplied hostname\n" "%s != %s\n", buf, host ); return( -1 ); } return( 0 ); }
int main(int argc, char **argv) { LHASH *conf; X509 *cert; FILE *inf; char *conf_file; int i; int count; X509_EXTENSION *ext; X509V3_add_standard_extensions(); ERR_load_crypto_strings(); if (!argv[1]) { fprintf(stderr, "Usage: v3conf cert.pem [file.cnf]\n"); exit(1); } conf_file = argv[2]; if (!conf_file) conf_file = "test.cnf"; conf = CONF_load(NULL, "test.cnf", NULL); if (!conf) { fprintf(stderr, "Error opening Config file %s\n", conf_file); ERR_print_errors_fp(stderr); exit(1); } inf = fopen(argv[1], "r"); if (!inf) { fprintf(stderr, "Can't open certificate file %s\n", argv[1]); exit(1); } cert = PEM_read_X509(inf, NULL, NULL); if (!cert) { fprintf(stderr, "Error reading certificate file %s\n", argv[1]); exit(1); } fclose(inf); sk_pop_free(cert->cert_info->extensions, X509_EXTENSION_free); cert->cert_info->extensions = NULL; if (!X509V3_EXT_add_conf(conf, NULL, "test_section", cert)) { fprintf(stderr, "Error adding extensions\n"); ERR_print_errors_fp(stderr); exit(1); } count = X509_get_ext_count(cert); printf("%d extensions\n", count); for (i = 0; i < count; i++) { ext = X509_get_ext(cert, i); printf("%s", OBJ_nid2ln(OBJ_obj2nid(ext->object))); if (ext->critical) printf(",critical:\n"); else printf(":\n"); X509V3_EXT_print_fp(stdout, ext, 0, 0); printf("\n"); } return 0; }
int ca_x509_subjectaltname(X509 *cert, struct iked_id *id) { X509_EXTENSION *san; uint8_t sanhdr[4], *data; int ext, santype, sanlen; char idstr[IKED_ID_SIZE]; if ((ext = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1)) == -1 || ((san = X509_get_ext(cert, ext)) == NULL)) { log_debug("%s: did not find subjectAltName in certificate", __func__); return (-1); } if (san->value == NULL || san->value->data == NULL || san->value->length < (int)sizeof(sanhdr)) { log_debug("%s: invalid subjectAltName in certificate", __func__); return (-1); } /* This is partially based on isakmpd's x509 subjectaltname code */ data = (uint8_t *)san->value->data; memcpy(&sanhdr, data, sizeof(sanhdr)); santype = sanhdr[2] & 0x3f; sanlen = sanhdr[3]; if ((sanlen + (int)sizeof(sanhdr)) > san->value->length) { log_debug("%s: invalid subjectAltName length", __func__); return (-1); } switch (santype) { case GEN_DNS: id->id_type = IKEV2_ID_FQDN; break; case GEN_EMAIL: id->id_type = IKEV2_ID_UFQDN; break; case GEN_IPADD: if (sanlen == 4) id->id_type = IKEV2_ID_IPV4; else if (sanlen == 16) id->id_type = IKEV2_ID_IPV6; else { log_debug("%s: invalid subjectAltName IP address", __func__); return (-1); } break; default: log_debug("%s: unsupported subjectAltName type %d", __func__, santype); return (-1); } ibuf_release(id->id_buf); if ((id->id_buf = ibuf_new(data + sizeof(sanhdr), sanlen)) == NULL) { log_debug("%s: failed to get id buffer", __func__); return (-1); } id->id_offset = 0; ikev2_print_id(id, idstr, sizeof(idstr)); log_debug("%s: %s", __func__, idstr); return (0); }
static void x509v3_cache_extensions(X509 *x) { BASIC_CONSTRAINTS *bs; PROXY_CERT_INFO_EXTENSION *pci; ASN1_BIT_STRING *usage; ASN1_BIT_STRING *ns; EXTENDED_KEY_USAGE *extusage; X509_EXTENSION *ex; int i; if(x->ex_flags & EXFLAG_SET) return; #ifndef OPENSSL_NO_SHA X509_digest(x, EVP_sha1(), x->sha1_hash, NULL); #endif /* Does subject name match issuer ? */ if(!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x))) x->ex_flags |= EXFLAG_SS; /* V1 should mean no extensions ... */ if(!X509_get_version(x)) x->ex_flags |= EXFLAG_V1; /* Handle basic constraints */ if((bs=X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL))) { if(bs->ca) x->ex_flags |= EXFLAG_CA; if(bs->pathlen) { if((bs->pathlen->type == V_ASN1_NEG_INTEGER) || !bs->ca) { x->ex_flags |= EXFLAG_INVALID; x->ex_pathlen = 0; } else x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen); } else x->ex_pathlen = -1; BASIC_CONSTRAINTS_free(bs); x->ex_flags |= EXFLAG_BCONS; } /* Handle proxy certificates */ if((pci=X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) { if (x->ex_flags & EXFLAG_CA || X509_get_ext_by_NID(x, NID_subject_alt_name, 0) >= 0 || X509_get_ext_by_NID(x, NID_issuer_alt_name, 0) >= 0) { x->ex_flags |= EXFLAG_INVALID; } if (pci->pcPathLengthConstraint) { x->ex_pcpathlen = ASN1_INTEGER_get(pci->pcPathLengthConstraint); } else x->ex_pcpathlen = -1; PROXY_CERT_INFO_EXTENSION_free(pci); x->ex_flags |= EXFLAG_PROXY; } /* Handle key usage */ if((usage=X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) { if(usage->length > 0) { x->ex_kusage = usage->data[0]; if(usage->length > 1) x->ex_kusage |= usage->data[1] << 8; } else x->ex_kusage = 0; x->ex_flags |= EXFLAG_KUSAGE; ASN1_BIT_STRING_free(usage); } x->ex_xkusage = 0; if((extusage=X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL))) { x->ex_flags |= EXFLAG_XKUSAGE; for(i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) { switch(OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage,i))) { case NID_server_auth: x->ex_xkusage |= XKU_SSL_SERVER; break; case NID_client_auth: x->ex_xkusage |= XKU_SSL_CLIENT; break; case NID_email_protect: x->ex_xkusage |= XKU_SMIME; break; case NID_code_sign: x->ex_xkusage |= XKU_CODE_SIGN; break; case NID_ms_sgc: case NID_ns_sgc: x->ex_xkusage |= XKU_SGC; break; case NID_OCSP_sign: x->ex_xkusage |= XKU_OCSP_SIGN; break; case NID_time_stamp: x->ex_xkusage |= XKU_TIMESTAMP; break; case NID_dvcs: x->ex_xkusage |= XKU_DVCS; break; } } sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free); } if((ns=X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL))) { if(ns->length > 0) x->ex_nscert = ns->data[0]; else x->ex_nscert = 0; x->ex_flags |= EXFLAG_NSCERT; ASN1_BIT_STRING_free(ns); } x->skid =X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL); x->akid =X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL); for (i = 0; i < X509_get_ext_count(x); i++) { ex = X509_get_ext(x, i); if (!X509_EXTENSION_get_critical(ex)) continue; if (!X509_supported_extension(ex)) { x->ex_flags |= EXFLAG_CRITICAL; break; } } x->ex_flags |= EXFLAG_SET; }
gboolean tls_verify_certificate_name(X509 *cert, const gchar *host_name) { gchar pattern_buf[256]; gint ext_ndx; gboolean found = FALSE, result = FALSE; ext_ndx = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1); if (ext_ndx >= 0) { /* ok, there's a subjectAltName extension, check that */ X509_EXTENSION *ext; STACK_OF(GENERAL_NAME) *alt_names; GENERAL_NAME *gen_name; ext = X509_get_ext(cert, ext_ndx); alt_names = X509V3_EXT_d2i(ext); if (alt_names) { gint num, i; num = sk_GENERAL_NAME_num(alt_names); for (i = 0; !result && i < num; i++) { gen_name = sk_GENERAL_NAME_value(alt_names, i); if (gen_name->type == GEN_DNS) { guchar *dnsname = ASN1_STRING_data(gen_name->d.dNSName); guint dnsname_len = ASN1_STRING_length(gen_name->d.dNSName); if (dnsname_len > sizeof(pattern_buf) - 1) { found = TRUE; result = FALSE; break; } memcpy(pattern_buf, dnsname, dnsname_len); pattern_buf[dnsname_len] = 0; /* we have found a DNS name as alternative subject name */ found = TRUE; result = tls_wildcard_match(host_name, pattern_buf); } else if (gen_name->type == GEN_IPADD) { char *dotted_ip = inet_ntoa(*(struct in_addr *) gen_name->d.iPAddress->data); g_strlcpy(pattern_buf, dotted_ip, sizeof(pattern_buf)); found = TRUE; result = strcasecmp(host_name, pattern_buf) == 0; } } sk_GENERAL_NAME_free(alt_names); } } if (!found) { /* hmm. there was no subjectAltName (this is deprecated, but still * widely used), look up the Subject, most specific CN */ X509_NAME *name; name = X509_get_subject_name(cert); if (X509_NAME_get_text_by_NID(name, NID_commonName, pattern_buf, sizeof(pattern_buf)) != -1) { result = tls_wildcard_match(host_name, pattern_buf); } } if (!result) { msg_error("Certificate subject does not match configured hostname", evt_tag_str("hostname", host_name), evt_tag_str("certificate", pattern_buf), NULL); } else { msg_verbose("Certificate subject matches configured hostname", evt_tag_str("hostname", host_name), evt_tag_str("certificate", pattern_buf), NULL); } return result; }