/* char *value: Value */ static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid, int crit, char *value) { X509V3_EXT_METHOD *method; X509_EXTENSION *ext; STACK_OF(CONF_VALUE) *nval; void *ext_struc; if (ext_nid == NID_undef) { X509V3err(X509V3_F_DO_EXT_NCONF,X509V3_R_UNKNOWN_EXTENSION_NAME); return NULL; } if (!(method = X509V3_EXT_get_nid(ext_nid))) { X509V3err(X509V3_F_DO_EXT_NCONF,X509V3_R_UNKNOWN_EXTENSION); return NULL; } /* Now get internal extension representation based on type */ if (method->v2i) { if(*value == '@') nval = NCONF_get_section(conf, value + 1); else nval = X509V3_parse_list(value); if(sk_CONF_VALUE_num(nval) <= 0) { X509V3err(X509V3_F_DO_EXT_NCONF,X509V3_R_INVALID_EXTENSION_STRING); ERR_add_error_data(4, "name=", OBJ_nid2sn(ext_nid), ",section=", value); return NULL; } ext_struc = method->v2i(method, ctx, nval); if(*value != '@') sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); if(!ext_struc) return NULL; } else if(method->s2i) { if(!(ext_struc = method->s2i(method, ctx, value))) return NULL; } else if(method->r2i) { if(!ctx->db || !ctx->db_meth) { X509V3err(X509V3_F_DO_EXT_NCONF,X509V3_R_NO_CONFIG_DATABASE); return NULL; } if(!(ext_struc = method->r2i(method, ctx, value))) return NULL; } else { X509V3err(X509V3_F_DO_EXT_NCONF,X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED); ERR_add_error_data(2, "name=", OBJ_nid2sn(ext_nid)); return NULL; } ext = do_ext_i2d(method, ext_nid, crit, ext_struc); if(method->it) ASN1_item_free(ext_struc, ASN1_ITEM_ptr(method->it)); else method->ext_free(ext_struc); return ext; }
EXPORT_C void *X509V3_EXT_d2i(X509_EXTENSION *ext) { X509V3_EXT_METHOD *method; const unsigned char *p; if(!(method = X509V3_EXT_get(ext))) return NULL; p = ext->value->data; if(method->it) return ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it)); return method->d2i(NULL, &p, ext->value->length); }
int protocol_checkcert(void *peer, X509 * cert) { struct in_network net; int i, j; const unsigned char *p; void *ext_str = NULL; const STACK_OF(X509_EXTENSION) * exts = cert->cert_info->extensions; X509_EXTENSION *ext; X509V3_EXT_METHOD *method; STACK_OF(GENERAL_SUBTREE) * trees; GENERAL_SUBTREE *tree; for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { ext = sk_X509_EXTENSION_value(exts, i); if ((method = X509V3_EXT_get(ext)) && method->ext_nid == NID_name_constraints) { p = ext->value->data; if (method->it) ext_str = ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it)); else ext_str = method->d2i(NULL, &p, ext->value->length); trees = ((NAME_CONSTRAINTS *) ext_str)->permittedSubtrees; for (j = 0; j < sk_GENERAL_SUBTREE_num(trees); j++) { tree = sk_GENERAL_SUBTREE_value(trees, j); if (tree->base->type == GEN_IPADD) p = tree->base->d.ip->data; if (tree->base->d.ip->length == 8) { net.addr.s_addr = *((uint32_t *) p); net.netmask.s_addr = *((uint32_t *) & p[4]); printf("%s/", inet_ntoa(net.addr)); printf("%s\n", inet_ntoa(net.netmask)); } //else if(len == 32) //IPv6 // See openssl/crypto/x509v3/v3_ncons.c:static int print_nc_ipadd() //else //DNS // GENERAL_NAME_print(bp, tree->base); } } } return 0; }
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; }
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; }
/* * 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; }
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; }
/** 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\n"); } 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; 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, host) ) || (!strcasecmp(nval->name, "iPAddress") && !strcasecmp(nval->value, host))) { verb ("V: subjectAltName matched: %s, type: %s\n", nval->value, nval->name); // We matched this; so it's safe to print ok = 1; break; } verb ("V: subjectAltName found but not matched: %s, type: %s\n", nval->value, nval->name); // XXX: Clean this string! } } } else { verb ("V: found non subjectAltName extension\n"); } if (ok) { break; } } } else { verb ("V: no X509_EXTENSION field(s) found\n"); } X509_free(cert); return ok; }
long ipfix_ssl_post_connection_check(SSL *ssl, char *host) { X509 *cert; X509_NAME *subj; char data[256]; int extcount; int ok = 0; /* Checking the return from SSL_get_peer_certificate here is not strictly * necessary. */ if (!(cert = SSL_get_peer_certificate(ssl)) || !host) goto err_occured; if ((extcount = X509_get_ext_count(cert)) > 0) { int i; for (i = 0; i < extcount; i++) { char *extstr; X509_EXTENSION *ext; ext = X509_get_ext(cert, i); extstr = (char*) OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); if (!strcmp(extstr, "subjectAltName")) { int j; const unsigned char *data; STACK_OF(CONF_VALUE) *val; CONF_VALUE *nval; X509V3_EXT_METHOD *meth; void *ext_str = NULL; if (!(meth = X509V3_EXT_get(ext))) break; data = ext->value->data; #if (OPENSSL_VERSION_NUMBER > 0x00907000L) if (meth->it) ext_str = ASN1_item_d2i(NULL, &data, ext->value->length, ASN1_ITEM_ptr(meth->it)); else ext_str = meth->d2i(NULL, &data, ext->value->length); #else ext_str = meth->d2i(NULL, &data, ext->value->length); #endif val = meth->i2v(meth, ext_str, 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, host)) { ok = 1; break; } } } if (ok) break; } } if (!ok && (subj = X509_get_subject_name(cert)) && X509_NAME_get_text_by_NID(subj, NID_commonName, data, 256) > 0) { data[255] = 0; if (strcasecmp(data, host) != 0) goto err_occured; } X509_free(cert); return SSL_get_verify_result(ssl); err_occured: if (cert) X509_free(cert); return X509_V_ERR_APPLICATION_VERIFICATION; }
int certproc(int netsock, int filesock) { char *csr, *chain, *url; unsigned char *csrcp, *chaincp; size_t csrsz, chainsz; int i, rc, idx, cc; enum certop op; long lval; X509 *x, *chainx; X509_EXTENSION *ext; X509V3_EXT_METHOD *method; void *entries; STACK_OF(CONF_VALUE) *val; CONF_VALUE *nval; ext = NULL; idx = -1; method = NULL; chain = csr = url = NULL; rc = 0; x = chainx = NULL; /* File-system and sandbox jailing. */ if ( ! sandbox_before()) goto out; ERR_load_crypto_strings(); if ( ! dropfs(PATH_VAR_EMPTY)) goto out; else if ( ! dropprivs()) goto out; else if ( ! sandbox_after()) goto out; /* Read what the netproc wants us to do. */ op = CERT__MAX; if (0 == (lval = readop(netsock, COMM_CSR_OP))) op = CERT_STOP; else if (CERT_REVOKE == lval || CERT_UPDATE == lval) op = lval; if (CERT_STOP == op) { rc = 1; goto out; } else if (CERT__MAX == op) { warnx("unknown operation from netproc"); goto out; } /* * Pass revocation right through to fileproc. * If the reader is terminated, ignore it. */ if (CERT_REVOKE == op) { if (writeop(filesock, COMM_CHAIN_OP, FILE_REMOVE) >= 0) rc = 1; goto out; } /* * Wait until we receive the DER encoded (signed) certificate * from the network process. * Then convert the DER encoding into an X509 certificate. */ if (NULL == (csr = readbuf(netsock, COMM_CSR, &csrsz))) goto out; csrcp = (u_char *)csr; x = d2i_X509(NULL, (const u_char **)&csrcp, csrsz); if (NULL == x) { warnx("d2i_X509"); goto out; } /* * Extract the CA Issuers from its NID. * TODO: I have no idea what I'm doing. */ idx = X509_get_ext_by_NID(x, NID_info_access, idx); if (idx >= 0 && NULL != (ext = X509_get_ext(x, idx))) method = (X509V3_EXT_METHOD *)X509V3_EXT_get(ext); entries = X509_get_ext_d2i(x, NID_info_access, 0, 0); if (NULL != method && NULL != entries) { val = method->i2v(method, entries, 0); for (i = 0; i < sk_CONF_VALUE_num(val); i++) { nval = sk_CONF_VALUE_value(val, i); if (strcmp(nval->name, "CA Issuers - URI")) continue; url = strdup(nval->value); if (NULL == url) { warn("strdup"); goto out; } break; } } if (NULL == url) { warnx("no CA issuer registered with certificate"); goto out; } /* Write the CA issuer to the netsock. */ if (writestr(netsock, COMM_ISSUER, url) <= 0) goto out; /* Read the full-chain back from the netsock. */ if (NULL == (chain = readbuf(netsock, COMM_CHAIN, &chainsz))) goto out; /* * Then check if the chain is PEM-encoded by looking to see if * it begins with the PEM marker. * If so, ship it as-is; otherwise, convert to a PEM encoded * buffer and ship that. * FIXME: if PEM, re-parse it. */ if (chainsz <= strlen(MARKER) || strncmp(chain, MARKER, strlen(MARKER))) { chaincp = (u_char *)chain; chainx = d2i_X509(NULL, (const u_char **)&chaincp, chainsz); if (NULL == chainx) { warnx("d2i_X509"); goto out; } free(chain); if (NULL == (chain = x509buf(chainx, &chainsz))) goto out; } /* Allow reader termination to just push us out. */ if (0 == (cc = writeop(filesock, COMM_CHAIN_OP, FILE_CREATE))) rc = 1; if (cc <= 0) goto out; if (0 == (cc = writebuf(filesock, COMM_CHAIN, chain, chainsz))) rc = 1; if (cc <= 0) goto out; /* * Next, convert the X509 to a buffer and send that. * Reader failure doesn't change anything. */ free(chain); if (NULL == (chain = x509buf(x, &chainsz))) goto out; if (writebuf(filesock, COMM_CSR, chain, chainsz) < 0) goto out; rc = 1; out: close(netsock); close(filesock); if (NULL != x) X509_free(x); if (NULL != chainx) X509_free(chainx); free(csr); free(url); free(chain); ERR_print_errors_fp(stderr); ERR_free_strings(); return(rc); }