static int get_comp(str* res, int local, int issuer, int nid, sip_msg_t* msg) { static char buf[1024]; X509* cert; struct tcp_connection* c; X509_NAME* name; X509_NAME_ENTRY* e; ASN1_STRING* asn1; int index, text_len; char* elem; unsigned char* text_s; text_s = 0; if (get_cert(&cert, &c, msg, local) < 0) return -1; name = issuer ? X509_get_issuer_name(cert) : X509_get_subject_name(cert); if (!name) { ERR("Cannot extract subject or issuer name from peer certificate\n"); goto err; } index = X509_NAME_get_index_by_NID(name, nid, -1); if (index == -1) { switch(nid) { case NID_commonName: elem = "CommonName"; break; case NID_organizationName: elem = "OrganizationName"; break; case NID_organizationalUnitName: elem = "OrganizationalUnitUname"; break; case NID_countryName: elem = "CountryName"; break; case NID_stateOrProvinceName: elem = "StateOrProvinceName"; break; case NID_localityName: elem = "LocalityName"; break; case NID_userId: elem = "UserID"; break; default: elem = "Unknown"; break; } DBG("Element %s not found in certificate subject/issuer\n", elem); goto err; } e = X509_NAME_get_entry(name, index); asn1 = X509_NAME_ENTRY_get_data(e); text_len = ASN1_STRING_to_UTF8(&text_s, asn1); if (text_len < 0 || text_len >= 1024) { ERR("Error converting ASN1 string\n"); goto err; } memcpy(buf, text_s, text_len); res->s = buf; res->len = text_len; OPENSSL_free(text_s); if (!local) X509_free(cert); tcpconn_put(c); return 0; err: if (text_s) OPENSSL_free(text_s); if (!local) X509_free(cert); tcpconn_put(c); return -1; }
int tlsops_sn(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { static char buf[INT2STR_MAX_LEN]; X509* cert; struct tcp_connection* c; int my, serial; char* sn; if (param->pvn.u.isname.name.n & CERT_PEER) { my = 0; } else if (param->pvn.u.isname.name.n & CERT_LOCAL) { my = 1; } else { LM_CRIT("could not determine certificate\n"); return pv_get_null(msg, param, res); } if (get_cert(&cert, &c, msg, my) < 0) return pv_get_null(msg, param, res); serial = ASN1_INTEGER_get(X509_get_serialNumber(cert)); sn = int2str( serial, &res->rs.len); memcpy(buf, sn, res->rs.len); res->rs.s = buf; res->ri = serial; res->flags = PV_VAL_STR | PV_VAL_INT; if (!my) X509_free(cert); tcpconn_put(c); return 0; }
int tlsops_cert_version(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { static char buf[INT2STR_MAX_LEN]; X509* cert; struct tcp_connection* c; char* version; int my; if (param->pvn.u.isname.name.n & CERT_PEER) { my = 0; } else if (param->pvn.u.isname.name.n & CERT_LOCAL) { my = 1; } else { LM_CRIT("bug in call to tlsops_cert_version\n"); return pv_get_null(msg, param, res); } if (get_cert(&cert, &c, msg, my) < 0) return -1; version = int2str(X509_get_version(cert), &res->rs.len); memcpy(buf, version, res->rs.len); res->rs.s = buf; res->flags = PV_VAL_STR; if (!my) X509_free(cert); tcpconn_put(c); return 0; }
static int test_ocsp_url_svcloc_new(void) { static const char * urls[] = { "www.openssl.org", "www.openssl.net", NULL }; X509 *issuer = NULL; X509_EXTENSION * ext = NULL; int ret = 0; if (!TEST_true(get_cert(&issuer))) goto err; /* * Test calling this ocsp method to catch any memory leak */ ext = OCSP_url_svcloc_new(X509_get_issuer_name(issuer), urls); if (!TEST_ptr(ext)) goto err; X509_EXTENSION_free(ext); ret = 1; err: X509_free(issuer); return ret; }
STACK_OF(X509) *get_cert_store(int *ids){ STACK_OF(X509) *store = sk_X509_new(NULL); while(ids && ((*ids) != -1)){ sk_X509_push(store, get_cert(*ids)); ids++; } return store; }
static int get_validity(str* res, int local, int bound, sip_msg_t* msg) { #define NOT_BEFORE 0 #define NOT_AFTER 1 static char buf[1024]; X509* cert; struct tcp_connection* c; BUF_MEM* p; BIO* mem = 0; ASN1_TIME* date; if (get_cert(&cert, &c, msg, local) < 0) return -1; switch (bound) { case NOT_BEFORE: date = X509_get_notBefore(cert); break; case NOT_AFTER: date = X509_get_notAfter(cert); break; default: BUG("Unexpected parameter value \"%d\"\n", bound); goto err; } mem = BIO_new(BIO_s_mem()); if (!mem) { ERR("Error while creating memory BIO\n"); goto err; } if (!ASN1_TIME_print(mem, date)) { ERR("Error while printing certificate date/time\n"); goto err; } BIO_get_mem_ptr(mem, &p); if (p->length >= 1024) { ERR("Date/time too long\n"); goto err; } memcpy(buf, p->data, p->length); res->s = buf; res->len = p->length; BIO_free(mem); if (!local) X509_free(cert); tcpconn_put(c); return 0; err: if (mem) BIO_free(mem); if (!local) X509_free(cert); tcpconn_put(c); return -1; }
int tlsops_validity(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { static char buf[1024]; X509* cert; struct tcp_connection* c; BUF_MEM* p; BIO* mem = 0; ASN1_TIME* date; int my = 0; if (get_cert(&cert, &c, msg, my) < 0) return -1; switch (param->pvn.u.isname.name.n) { case CERT_NOTBEFORE: date = X509_get_notBefore(cert); break; case CERT_NOTAFTER: date = X509_get_notAfter(cert); break; default: LM_CRIT("unexpected parameter value \"%d\"\n", param->pvn.u.isname.name.n); goto err; } mem = BIO_new(BIO_s_mem()); if (!mem) { LM_ERR("failed to create memory BIO\n"); goto err; } if (!ASN1_TIME_print(mem, date)) { LM_ERR("failed to print certificate date/time\n"); goto err; } BIO_get_mem_ptr(mem, &p); if (p->length >= 1024) { LM_ERR("Date/time too long\n"); goto err; } memcpy(buf, p->data, p->length); res->rs.s = buf; res->rs.len = p->length; res->flags = PV_VAL_STR ; BIO_free(mem); if (!my) X509_free(cert); tcpconn_put(c); return 0; err: if (mem) BIO_free(mem); if (!my) X509_free(cert); tcpconn_put(c); return pv_get_null(msg, param, res); }
int main(int argc,char *argv[]) { unsigned char *fpr; size_t fpr_len; char *url; int rc; IOBUF iobuf; if(argc!=2) { printf("cert-test [name]\n"); return 1; } printf("CERT lookup on %s\n",argv[1]); rc=get_cert(argv[1],16384,&iobuf,&fpr,&fpr_len,&url); if(rc==-1) printf("error\n"); else if(rc==0) printf("no answer\n"); else if(rc==1) { printf("key found: %d bytes\n",(int)iobuf_get_temp_length(iobuf)); iobuf_close(iobuf); } else if(rc==2) { if(fpr) { size_t i; printf("Fingerprint found (%d bytes): ",(int)fpr_len); for(i=0;i<fpr_len;i++) printf("%02X",fpr[i]); printf("\n"); } else printf("No fingerprint found\n"); if(url) printf("URL found: %s\n",url); else printf("No URL found\n"); xfree(fpr); xfree(url); } return 0; }
static const char *obtain_cert(const char *hostname, const char *proto, unsigned port, const char *app_proto, unsigned quiet) { socket_st hd; char txt_port[16]; unsigned udp = 0; static char tmpfile[32]; int fd, ret; const char *str = "Obtaining certificate from"; const char *service; if (strcmp(proto, "udp") == 0) udp = 1; else if (strcmp(proto, "tcp") != 0) { /* we cannot handle this protocol */ return NULL; } strcpy(tmpfile, "danetool-certXXXXXX"); sockets_init(); snprintf(txt_port, sizeof(txt_port), "%u", port); if (quiet) str = NULL; service = port_to_service(txt_port, proto); socket_open(&hd, hostname, service, udp, str); if (app_proto == NULL) app_proto = service; socket_starttls(&hd, app_proto); umask(066); fd = mkstemp(tmpfile); if (fd == -1) { int e = errno; fprintf(stderr, "error[%d]: %s\n", __LINE__, strerror(e)); exit(1); } ret = get_cert(&hd, hostname, udp, fd); close(fd); socket_bye(&hd); if (ret == -1) return NULL; else return tmpfile; }
static int get_cert_version(str* res, int local, sip_msg_t* msg) { static char buf[INT2STR_MAX_LEN]; X509* cert; struct tcp_connection* c; char* version; if (get_cert(&cert, &c, msg, local) < 0) return -1; version = int2str(X509_get_version(cert), &res->len); memcpy(buf, version, res->len); res->s = buf; if (!local) X509_free(cert); tcpconn_put(c); return 0; }
static int get_sn(str* res, int* ires, int local, sip_msg_t* msg) { static char buf[INT2STR_MAX_LEN]; X509* cert; struct tcp_connection* c; char* sn; int num; if (get_cert(&cert, &c, msg, local) < 0) return -1; num = ASN1_INTEGER_get(X509_get_serialNumber(cert)); sn = int2str(num, &res->len); memcpy(buf, sn, res->len); res->s = buf; if (ires) *ires = num; if (!local) X509_free(cert); tcpconn_put(c); return 0; }
/* * Initialize SSL/TLS connection. */ int open_secure_connection(session *ssn) { int r, e; SSL_CTX *ctx; if (!ssn->sslproto) { ctx = ssl23ctx; } else if (!strcasecmp(ssn->sslproto, "ssl3")) { ctx = ssl3ctx; } else if (!strcasecmp(ssn->sslproto, "tls1")) { ctx = tls1ctx; } else if (!strcasecmp(ssn->sslproto, "tls1.1")) { #if OPENSSL_VERSION_NUMBER >= 0x01000100fL ctx = tls11ctx; #else ctx = tls1ctx; #endif } else if (!strcasecmp(ssn->sslproto, "tls1.2")) { #if OPENSSL_VERSION_NUMBER >= 0x01000100fL ctx = tls12ctx; #else ctx = tls1ctx; #endif } else { ctx = ssl23ctx; } if (!(ssn->sslconn = SSL_new(ctx))) goto fail; SSL_set_fd(ssn->sslconn, ssn->socket); for (;;) { if ((r = SSL_connect(ssn->sslconn)) > 0) break; switch (SSL_get_error(ssn->sslconn, r)) { case SSL_ERROR_ZERO_RETURN: error("initiating SSL connection to %s; the " "connection has been closed cleanly\n", ssn->server); goto fail; case SSL_ERROR_NONE: case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_ACCEPT: case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: break; case SSL_ERROR_SYSCALL: e = ERR_get_error(); if (e == 0 && r == 0) error("initiating SSL connection to %s; EOF in " "violation of the protocol\n", ssn->server); else if (e == 0 && r == -1) error("initiating SSL connection to %s; %s\n", ssn->server, strerror(errno)); else error("initiating SSL connection to %s; %s\n", ssn->server, ERR_error_string(e, NULL)); goto fail; case SSL_ERROR_SSL: error("initiating SSL connection to %s; %s\n", ssn->server, ERR_error_string(ERR_get_error(), NULL)); goto fail; default: break; } } if (get_option_boolean("certificates") && get_cert(ssn) == -1) goto fail; return 0; fail: ssn->sslconn = NULL; return -1; }
int tlsops_alt(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { static char buf[1024]; int type = GEN_URI, my = 0, n, found = 0, ind_local; STACK_OF(GENERAL_NAME)* names = 0; GENERAL_NAME* nm; X509* cert; struct tcp_connection* c; str text; struct ip_addr ip; ind_local = param->pvn.u.isname.name.n; if (ind_local & CERT_PEER) { my = 0; ind_local = ind_local ^ CERT_PEER; } else if (ind_local & CERT_LOCAL) { my = 1; ind_local = ind_local ^ CERT_LOCAL; } else { LM_CRIT("could not determine certificate\n"); return pv_get_null(msg, param, res); } switch(ind_local) { case COMP_E: type = GEN_EMAIL; break; case COMP_HOST: type = GEN_DNS; break; case COMP_URI: type = GEN_URI; break; case COMP_IP: type = GEN_IPADD; break; default: LM_CRIT("ind_local=%d\n", ind_local); return pv_get_null(msg, param, res); } if (get_cert(&cert, &c, msg, my) < 0) return -1; names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (!names) { LM_ERR("cannot get certificate alternative subject\n"); goto err; } for (n = 0; n < sk_GENERAL_NAME_num(names); n++) { nm = sk_GENERAL_NAME_value(names, n); if (nm->type != type) continue; switch(type) { case GEN_EMAIL: case GEN_DNS: case GEN_URI: text.s = (char*)nm->d.ia5->data; text.len = nm->d.ia5->length; if (text.len >= 1024) { LM_ERR("alternative subject text too long\n"); goto err; } memcpy(buf, text.s, text.len); res->rs.s = buf; res->rs.len = text.len; res->flags = PV_VAL_STR; found = 1; break; case GEN_IPADD: ip.len = nm->d.iPAddress->length; ip.af = (ip.len == 16) ? AF_INET6 : AF_INET; memcpy(ip.u.addr, nm->d.iPAddress->data, ip.len); text.s = ip_addr2a(&ip); text.len = strlen(text.s); memcpy(buf, text.s, text.len); res->rs.s = buf; res->rs.len = text.len; res->flags = PV_VAL_STR; found = 1; break; } break; } if (!found) goto err; if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); if (!my) X509_free(cert); tcpconn_put(c); return 0; err: if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); if (!my) X509_free(cert); tcpconn_put(c); return pv_get_null(msg, param, res); }
int tlsops_comp(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { static char buf[1024]; X509* cert; struct tcp_connection* c; X509_NAME* name; X509_NAME_ENTRY* e; ASN1_STRING* asn1; int nid = NID_commonName, index, my = 0, issuer = 0, ind_local; char* elem; str text; text.s = 0; /* copy callback value as we modify it */ ind_local = param->pvn.u.isname.name.n; DBG("DEBUG:tlsops:tlsops_comp: ind_local = %x", ind_local); if (ind_local & CERT_PEER) { my = 0; ind_local = ind_local ^ CERT_PEER; } else if (ind_local & CERT_LOCAL) { my = 1; ind_local = ind_local ^ CERT_LOCAL; } else { LM_CRIT("could not determine certificate\n"); return pv_get_null(msg, param, res); } if (ind_local & CERT_SUBJECT) { issuer = 0; ind_local = ind_local ^ CERT_SUBJECT; } else if (ind_local & CERT_ISSUER) { issuer = 1; ind_local = ind_local ^ CERT_ISSUER; } else { LM_CRIT("could not determine subject or issuer\n"); return pv_get_null(msg, param, res); } switch(ind_local) { case COMP_CN: nid = NID_commonName; break; case COMP_O: nid = NID_organizationName; break; case COMP_OU: nid = NID_organizationalUnitName; break; case COMP_C: nid = NID_countryName; break; case COMP_ST: nid = NID_stateOrProvinceName; break; case COMP_L: nid = NID_localityName; break; default: nid = NID_undef; } if (get_cert(&cert, &c, msg, my) < 0) return -1; name = issuer ? X509_get_issuer_name(cert) : X509_get_subject_name(cert); if (!name) { LM_ERR("cannot extract subject or issuer name from peer" " certificate\n"); goto err; } if (nid == NID_undef) { /* dump the whole cert info into buf */ X509_NAME_oneline(name, buf, sizeof(buf)); res->rs.s = buf; res->rs.len = strlen(buf); res->flags = PV_VAL_STR; } else { index = X509_NAME_get_index_by_NID(name, nid, -1); if (index == -1) { switch(ind_local) { case COMP_CN: elem = "CommonName"; break; case COMP_O: elem = "OrganizationName"; break; case COMP_OU: elem = "OrganizationalUnitUname"; break; case COMP_C: elem = "CountryName"; break; case COMP_ST: elem = "StateOrProvinceName"; break; case COMP_L: elem = "LocalityName"; break; default: elem = "Unknown"; break; } DBG("DEBUG:tlsops:tlsops_comp: element %s not found in " "certificate subject/issuer\n", elem); goto err; } e = X509_NAME_get_entry(name, index); asn1 = X509_NAME_ENTRY_get_data(e); text.len = ASN1_STRING_to_UTF8((unsigned char**)(void*)&text.s, asn1); if (text.len < 0 || text.len >= 1024) { LM_ERR("failed to convert ASN1 string\n"); goto err; } memcpy(buf, text.s, text.len); res->rs.s = buf; res->rs.len = text.len; res->flags = PV_VAL_STR; OPENSSL_free(text.s); } if (!my) X509_free(cert); tcpconn_put(c); return 0; err: if (text.s) OPENSSL_free(text.s); if (!my) X509_free(cert); tcpconn_put(c); return pv_get_null(msg, param, res); }
static int get_alt(str* res, int local, int type, sip_msg_t* msg) { static char buf[1024]; int n, found = 0; STACK_OF(GENERAL_NAME)* names = 0; GENERAL_NAME* nm; X509* cert; struct tcp_connection* c; str text; struct ip_addr ip; if (get_cert(&cert, &c, msg, local) < 0) return -1; names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (!names) { DBG("Cannot get certificate alternative subject\n"); goto err; } for (n = 0; n < sk_GENERAL_NAME_num(names); n++) { nm = sk_GENERAL_NAME_value(names, n); if (nm->type != type) continue; switch(type) { case GEN_EMAIL: case GEN_DNS: case GEN_URI: text.s = (char*)nm->d.ia5->data; text.len = nm->d.ia5->length; if (text.len >= 1024) { ERR("Alternative subject text too long\n"); goto err; } memcpy(buf, text.s, text.len); res->s = buf; res->len = text.len; found = 1; break; case GEN_IPADD: ip.len = nm->d.iPAddress->length; ip.af = (ip.len == 16) ? AF_INET6 : AF_INET; memcpy(ip.u.addr, nm->d.iPAddress->data, ip.len); text.s = ip_addr2a(&ip); text.len = strlen(text.s); memcpy(buf, text.s, text.len); res->s = buf; res->len = text.len; found = 1; break; } break; } if (!found) goto err; if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); if (!local) X509_free(cert); tcpconn_put(c); return 0; err: if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); if (!local) X509_free(cert); tcpconn_put(c); return -1; }
/* * Initialize SSL/TLS connection. */ int open_secure_connection(session *ssn) { int r, e; SSL_CTX *ctx; #if OPENSSL_VERSION_NUMBER >= 0x1000000fL const SSL_METHOD *method; #else SSL_METHOD *method; #endif method = NULL; if (ssn->sslproto && (!strncasecmp(ssn->sslproto, "ssl3", 4) || !strncasecmp(ssn->sslproto, "ssl2", 4))) method = SSLv23_client_method(); else method = TLSv1_client_method(); if (!(ctx = SSL_CTX_new(method))) goto fail; if (!(ssn->sslconn = SSL_new(ctx))) goto fail; SSL_set_fd(ssn->sslconn, ssn->socket); for (;;) { if ((r = SSL_connect(ssn->sslconn)) > 0) break; switch (SSL_get_error(ssn->sslconn, r)) { case SSL_ERROR_ZERO_RETURN: error("initiating SSL connection to %s; the " "connection has been closed cleanly\n", ssn->server); goto fail; case SSL_ERROR_NONE: case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_ACCEPT: case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: break; case SSL_ERROR_SYSCALL: e = ERR_get_error(); if (e == 0 && r == 0) error("initiating SSL connection to %s; EOF in " "violation of the protocol\n", ssn->server); else if (e == 0 && r == -1) error("initiating SSL connection to %s; %s\n", ssn->server, strerror(errno)); else error("initiating SSL connection to %s; %s\n", ssn->server, ERR_error_string(e, NULL)); goto fail; case SSL_ERROR_SSL: error("initiating SSL connection to %s; %s\n", ssn->server, ERR_error_string(ERR_get_error(), NULL)); goto fail; default: break; } } if (get_option_boolean("certificates") && get_cert(ssn) == -1) goto fail; SSL_CTX_free(ctx); return 0; fail: ssn->sslconn = NULL; SSL_CTX_free(ctx); return -1; }