X509 * ca_by_subjectpubkey(X509_STORE *ctx, uint8_t *sig, size_t siglen) { STACK_OF(X509_OBJECT) *h; X509_OBJECT *xo; X509 *ca; int i; unsigned int len; uint8_t md[EVP_MAX_MD_SIZE]; h = ctx->objs; for (i = 0; i < sk_X509_OBJECT_num(h); i++) { xo = sk_X509_OBJECT_value(h, i); if (xo->type != X509_LU_X509) continue; ca = xo->data.x509; len = sizeof(md); ca_subjectpubkey_digest(ca, md, &len); if (len == siglen && memcmp(md, sig, len) == 0) return (ca); } return (NULL); }
X509 * ca_by_issuer(X509_STORE *ctx, X509_NAME *subject, struct iked_static_id *id) { STACK_OF(X509_OBJECT) *h; X509_OBJECT *xo; X509 *cert; int i; X509_NAME *issuer; if (subject == NULL) return (NULL); h = ctx->objs; for (i = 0; i < sk_X509_OBJECT_num(h); i++) { xo = sk_X509_OBJECT_value(h, i); if (xo->type != X509_LU_X509) continue; cert = xo->data.x509; if ((issuer = X509_get_issuer_name(cert)) == NULL) continue; else if (X509_NAME_cmp(subject, issuer) == 0) { if (ca_x509_subjectaltname_cmp(cert, id) != 0) continue; return (cert); } } return (NULL); }
int ca_reload(struct iked *env) { struct ca_store *store = env->sc_priv; uint8_t md[EVP_MAX_MD_SIZE]; char file[PATH_MAX]; struct iovec iov[2]; struct dirent *entry; STACK_OF(X509_OBJECT) *h; X509_OBJECT *xo; X509 *x509; DIR *dir; int i, len, iovcnt = 0; /* * Load CAs */ if ((dir = opendir(IKED_CA_DIR)) == NULL) return (-1); while ((entry = readdir(dir)) != NULL) { if ((entry->d_type != DT_REG) && (entry->d_type != DT_LNK)) continue; if (snprintf(file, sizeof(file), "%s%s", IKED_CA_DIR, entry->d_name) == -1) continue; if (!X509_load_cert_file(store->ca_calookup, file, X509_FILETYPE_PEM)) { log_warn("%s: failed to load ca file %s", __func__, entry->d_name); ca_sslerror(__func__); continue; } log_debug("%s: loaded ca file %s", __func__, entry->d_name); } closedir(dir); /* * Load CRLs for the CAs */ if ((dir = opendir(IKED_CRL_DIR)) == NULL) return (-1); while ((entry = readdir(dir)) != NULL) { if ((entry->d_type != DT_REG) && (entry->d_type != DT_LNK)) continue; if (snprintf(file, sizeof(file), "%s%s", IKED_CRL_DIR, entry->d_name) == -1) continue; if (!X509_load_crl_file(store->ca_calookup, file, X509_FILETYPE_PEM)) { log_warn("%s: failed to load crl file %s", __func__, entry->d_name); ca_sslerror(__func__); continue; } /* Only enable CRL checks if we actually loaded a CRL */ X509_STORE_set_flags(store->ca_cas, X509_V_FLAG_CRL_CHECK); log_debug("%s: loaded crl file %s", __func__, entry->d_name); } closedir(dir); /* * Save CAs signatures for the IKEv2 CERTREQ */ ibuf_release(env->sc_certreq); if ((env->sc_certreq = ibuf_new(NULL, 0)) == NULL) return (-1); h = store->ca_cas->objs; for (i = 0; i < sk_X509_OBJECT_num(h); i++) { xo = sk_X509_OBJECT_value(h, i); if (xo->type != X509_LU_X509) continue; x509 = xo->data.x509; len = sizeof(md); ca_subjectpubkey_digest(x509, md, &len); log_debug("%s: %s", __func__, x509->name); if (ibuf_add(env->sc_certreq, md, len) != 0) { ibuf_release(env->sc_certreq); return (-1); } } if (ibuf_length(env->sc_certreq)) { env->sc_certreqtype = IKEV2_CERT_X509_CERT; iov[0].iov_base = &env->sc_certreqtype; iov[0].iov_len = sizeof(env->sc_certreqtype); iovcnt++; iov[1].iov_base = ibuf_data(env->sc_certreq); iov[1].iov_len = ibuf_length(env->sc_certreq); iovcnt++; log_debug("%s: loaded %zu ca certificate%s", __func__, ibuf_length(env->sc_certreq) / SHA_DIGEST_LENGTH, ibuf_length(env->sc_certreq) == SHA_DIGEST_LENGTH ? "" : "s"); (void)proc_composev(&env->sc_ps, PROC_IKEV2, IMSG_CERTREQ, iov, iovcnt); } /* * Load certificates */ if ((dir = opendir(IKED_CERT_DIR)) == NULL) return (-1); while ((entry = readdir(dir)) != NULL) { if ((entry->d_type != DT_REG) && (entry->d_type != DT_LNK)) continue; if (snprintf(file, sizeof(file), "%s%s", IKED_CERT_DIR, entry->d_name) == -1) continue; if (!X509_load_cert_file(store->ca_certlookup, file, X509_FILETYPE_PEM)) { log_warn("%s: failed to load cert file %s", __func__, entry->d_name); ca_sslerror(__func__); continue; } log_debug("%s: loaded cert file %s", __func__, entry->d_name); } closedir(dir); h = store->ca_certs->objs; for (i = 0; i < sk_X509_OBJECT_num(h); i++) { xo = sk_X509_OBJECT_value(h, i); if (xo->type != X509_LU_X509) continue; x509 = xo->data.x509; (void)ca_validate_cert(env, NULL, x509, 0); } if (!env->sc_certreqtype) env->sc_certreqtype = store->ca_pubkey.id_type; log_debug("%s: local cert type %s", __func__, print_map(env->sc_certreqtype, ikev2_cert_map)); iov[0].iov_base = &env->sc_certreqtype; iov[0].iov_len = sizeof(env->sc_certreqtype); if (iovcnt == 0) iovcnt++; (void)proc_composev(&env->sc_ps, PROC_IKEV2, IMSG_CERTREQ, iov, iovcnt); return (0); }
static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, X509_OBJECT *ret) { BY_DIR *ctx; union { struct { X509 st_x509; X509_CINF st_x509_cinf; } x509; struct { X509_CRL st_crl; X509_CRL_INFO st_crl_info; } crl; } data; int ok=0; int i,j,k; unsigned long h; BUF_MEM *b=NULL; struct stat st; X509_OBJECT stmp,*tmp; const char *postfix=""; if (name == NULL) return(0); stmp.type=type; if (type == X509_LU_X509) { data.x509.st_x509.cert_info= &data.x509.st_x509_cinf; data.x509.st_x509_cinf.subject=name; stmp.data.x509= &data.x509.st_x509; postfix=""; } else if (type == X509_LU_CRL) { data.crl.st_crl.crl= &data.crl.st_crl_info; data.crl.st_crl_info.issuer=name; stmp.data.crl= &data.crl.st_crl; postfix="r"; } else { X509err(X509_F_GET_CERT_BY_SUBJECT,X509_R_WRONG_LOOKUP_TYPE); goto finish; } if ((b=BUF_MEM_new()) == NULL) { X509err(X509_F_GET_CERT_BY_SUBJECT,ERR_R_BUF_LIB); goto finish; } ctx=(BY_DIR *)xl->method_data; h=X509_NAME_hash(name); for (i=0; i<ctx->num_dirs; i++) { j=strlen(ctx->dirs[i])+1+8+6+1+1; if (!BUF_MEM_grow(b,j)) { X509err(X509_F_GET_CERT_BY_SUBJECT,ERR_R_MALLOC_FAILURE); goto finish; } k=0; for (;;) { char c = '/'; #ifdef OPENSSL_SYS_VMS c = ctx->dirs[i][strlen(ctx->dirs[i])-1]; if (c != ':' && c != '>' && c != ']') { /* If no separator is present, we assume the directory specifier is a logical name, and add a colon. We really should use better VMS routines for merging things like this, but this will do for now... -- Richard Levitte */ c = ':'; } else { c = '\0'; } #endif if (c == '\0') { /* This is special. When c == '\0', no directory separator should be added. */ BIO_snprintf(b->data,b->max, "%s%08lx.%s%d",ctx->dirs[i],h, postfix,k); } else { BIO_snprintf(b->data,b->max, "%s%c%08lx.%s%d",ctx->dirs[i],c,h, postfix,k); } k++; if (stat(b->data,&st) < 0) break; /* found one. */ if (type == X509_LU_X509) { if ((X509_load_cert_file(xl,b->data, ctx->dirs_type[i])) == 0) break; } else if (type == X509_LU_CRL) { if ((X509_load_crl_file(xl,b->data, ctx->dirs_type[i])) == 0) break; } /* else case will caught higher up */ } /* we have added it to the cache so now pull * it out again */ CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE); j = sk_X509_OBJECT_find(xl->store_ctx->objs,&stmp); if(j != -1) tmp=sk_X509_OBJECT_value(xl->store_ctx->objs,j); else tmp = NULL; CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE); if (tmp != NULL) { ok=1; ret->type=tmp->type; memcpy(&ret->data,&tmp->data,sizeof(ret->data)); /* If we were going to up the reference count, * we would need to do it on a perl 'type' * basis */ /* CRYPTO_add(&tmp->data.x509->references,1, CRYPTO_LOCK_X509);*/ goto finish; } } finish: if (b != NULL) BUF_MEM_free(b); return(ok); }
static int ldaplookup_by_subject( X509_LOOKUP *ctx, int type, X509_NAME *name, X509_OBJECT *ret ) { int count = 0; ldaphost *lh; const char *attrs[2]; char *filter = NULL; if (ctx == NULL) return(0); if (name == NULL) return(0); lh = (ldaphost*) ctx->method_data; if (lh == NULL) return(0); switch(type) { case X509_LU_X509: { attrs[0] = ATTR_CACERT; } break; case X509_LU_CRL: { attrs[0] = ATTR_CACRL; } break; default: { X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_WRONG_LOOKUP_TYPE); goto done; } } attrs[1] = NULL; filter = ldaplookup_filter(name, attrs[0]); if (filter == NULL) { X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_UNABLE_TO_GET_FILTER); goto done; } #ifdef TRACE_BY_LDAP fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject: filter=%s\n", filter); #endif for (; lh != NULL; lh = lh->next) { LDAPMessage *res = NULL; int result; #ifdef TRACE_BY_LDAP { int version = -1; ldap_get_option(lh->ld, LDAP_OPT_PROTOCOL_VERSION, &version); fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject:" " bind to \"%s://%s:%d\"" " using ldap v%d protocol\n" , lh->ldapurl->lud_scheme, lh->ldapurl->lud_host, lh->ldapurl->lud_port , version ); } #endif result = ldaplookup_bind_s(lh->ld); if (result != LDAP_SUCCESS) { X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_UNABLE_TO_BIND); { char buf[1024]; snprintf(buf, sizeof(buf), " url=\"%s://%s:%d\"" " ldaperror=0x%x(%.256s)" , lh->ldapurl->lud_scheme, lh->ldapurl->lud_host, lh->ldapurl->lud_port , result, ldap_err2string(result) ); ERR_add_error_data(1, buf); } continue; } result = ldaplookup_search_s(lh->ld, lh->ldapurl->lud_dn, LDAP_SCOPE_SUBTREE, filter, (char**)attrs, 0, &res); if (result != LDAP_SUCCESS) { X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_SEARCH_FAIL); ldap_msgfree(res); continue; } result = ldaplookup_result2store(type, name, lh->ld, res, ctx->store_ctx); if (result > 0) count += result; ldap_msgfree(res); /*do not call ldap_unbind_s*/ } #ifdef TRACE_BY_LDAP fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject: count=%d\n", count); #endif if (count > 0) { /* * we have added at least one to the cache so now pull one out again */ union { struct { X509_CINF st_x509_cinf; X509 st_x509; } x509; struct { X509_CRL_INFO st_crl_info; X509_CRL st_crl; } crl; } data; X509_OBJECT stmp, *tmp; int k; memset(&data, 0, sizeof(data)); stmp.type = type; switch(type) { case X509_LU_X509: { data.x509.st_x509_cinf.subject = name; data.x509.st_x509.cert_info = &data.x509.st_x509_cinf; stmp.data.x509 = &data.x509.st_x509; } break; case X509_LU_CRL: { data.crl.st_crl_info.issuer = name; data.crl.st_crl.crl = &data.crl.st_crl_info; stmp.data.crl = &data.crl.st_crl; } break; default: count = 0; goto done; } CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE); k = sk_X509_OBJECT_find(ctx->store_ctx->objs, &stmp); if (k >= 0) tmp = sk_X509_OBJECT_value(ctx->store_ctx->objs, k); else tmp = NULL; CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE); #ifdef TRACE_BY_LDAP fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject: k=%d, tmp=%p\n", k, (void*)tmp); #endif if (tmp == NULL) { count = 0; goto done; } ret->type = tmp->type; memcpy(&ret->data, &tmp->data, sizeof(ret->data)); } done: if (filter != NULL) OPENSSL_free(filter); return(count > 0); }