int x509_cert_get_subjects(void *scert, int *cnt, u_int8_t ***id, u_int32_t **id_len) { X509 *cert = scert; X509_NAME *subject; int type; u_int8_t *altname; u_int32_t altlen; u_int8_t *buf = 0; unsigned char *ubuf; int i; *id = 0; *id_len = 0; /* * XXX There can be a collection of subjectAltNames, but for now I * only return the subjectName and a single subjectAltName, if * present. */ type = x509_cert_subjectaltname(cert, &altname, &altlen); if (!type) { *cnt = 1; altlen = 0; } else *cnt = 2; *id = calloc(*cnt, sizeof **id); if (!*id) { log_print("x509_cert_get_subject: malloc (%lu) failed", *cnt * (unsigned long)sizeof **id); *cnt = 0; goto fail; } *id_len = calloc(*cnt, sizeof **id_len); if (!*id_len) { log_print("x509_cert_get_subject: malloc (%lu) failed", *cnt * (unsigned long)sizeof **id_len); goto fail; } /* Stash the subjectName into the first slot. */ subject = X509_get_subject_name(cert); if (!subject) goto fail; (*id_len)[0] = ISAKMP_ID_DATA_OFF + i2d_X509_NAME(subject, NULL) - ISAKMP_GEN_SZ; (*id)[0] = malloc((*id_len)[0]); if (!(*id)[0]) { log_print("x509_cert_get_subject: malloc (%d) failed", (*id_len)[0]); goto fail; } SET_ISAKMP_ID_TYPE((*id)[0] - ISAKMP_GEN_SZ, IPSEC_ID_DER_ASN1_DN); ubuf = (*id)[0] + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; i2d_X509_NAME(subject, &ubuf); if (altlen) { /* Stash the subjectAltName into the second slot. */ buf = malloc(altlen + ISAKMP_ID_DATA_OFF); if (!buf) { log_print("x509_cert_get_subject: malloc (%d) failed", altlen + ISAKMP_ID_DATA_OFF); goto fail; } switch (type) { case X509v3_DNS_NAME: SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_FQDN); break; case X509v3_RFC_NAME: SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_USER_FQDN); break; case X509v3_IP_ADDR: /* * XXX I dislike the numeric constants, but I don't * know what we should use otherwise. */ switch (altlen) { case 4: SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV4_ADDR); break; case 16: SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV6_ADDR); break; default: log_print("x509_cert_get_subject: invalid " "subjectAltName IPaddress length %d ", altlen); goto fail; } break; } SET_IPSEC_ID_PROTO(buf + ISAKMP_ID_DOI_DATA_OFF, 0); SET_IPSEC_ID_PORT(buf + ISAKMP_ID_DOI_DATA_OFF, 0); memcpy(buf + ISAKMP_ID_DATA_OFF, altname, altlen); (*id_len)[1] = ISAKMP_ID_DATA_OFF + altlen - ISAKMP_GEN_SZ; (*id)[1] = malloc((*id_len)[1]); if (!(*id)[1]) { log_print("x509_cert_get_subject: malloc (%d) failed", (*id_len)[1]); goto fail; } memcpy((*id)[1], buf + ISAKMP_GEN_SZ, (*id_len)[1]); free(buf); buf = 0; } return 1; fail: for (i = 0; i < *cnt; i++) free((*id)[i]); free(*id); free(*id_len); free(buf); return 0; }
int ike_phase_1_send_ID (struct message *msg) { struct exchange *exchange = msg->exchange; u_int8_t *buf; char header[80]; ssize_t sz; struct sockaddr *src; int initiator = exchange->initiator; u_int8_t **id; size_t *id_len; char *my_id = 0; u_int8_t id_type; /* Choose the right fields to fill-in. */ id = initiator ? &exchange->id_i : &exchange->id_r; id_len = initiator ? &exchange->id_i_len : &exchange->id_r_len; if (exchange->name) my_id = conf_get_str (exchange->name, "ID"); if (!my_id) my_id = conf_get_str ("General", "Default-phase-1-ID"); msg->transport->vtbl->get_src (msg->transport, &src); sz = my_id ? ipsec_id_size (my_id, &id_type) : sockaddr_addrlen (src); if (sz == -1) return -1; sz += ISAKMP_ID_DATA_OFF; buf = malloc (sz); if (!buf) { log_error ("ike_phase_1_send_ID: malloc (%lu) failed", (unsigned long)sz); return -1; } SET_IPSEC_ID_PROTO (buf + ISAKMP_ID_DOI_DATA_OFF, 0); SET_IPSEC_ID_PORT (buf + ISAKMP_ID_DOI_DATA_OFF, 0); if (my_id) { SET_ISAKMP_ID_TYPE (buf, id_type); switch (id_type) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: /* Already in network byteorder. */ memcpy (buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata (src), sockaddr_addrlen (src)); break; case IPSEC_ID_FQDN: case IPSEC_ID_USER_FQDN: case IPSEC_ID_KEY_ID: memcpy (buf + ISAKMP_ID_DATA_OFF, conf_get_str (my_id, "Name"), sz - ISAKMP_ID_DATA_OFF); break; default: log_print ("ike_phase_1_send_ID: unsupported ID type %d", id_type); free (buf); return -1; } } else { switch (src->sa_family) { case AF_INET: SET_ISAKMP_ID_TYPE (buf, IPSEC_ID_IPV4_ADDR); break; case AF_INET6: SET_ISAKMP_ID_TYPE (buf, IPSEC_ID_IPV6_ADDR); break; } /* Already in network byteorder. */ memcpy (buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata (src), sockaddr_addrlen (src)); } if (message_add_payload (msg, ISAKMP_PAYLOAD_ID, buf, sz, 1)) { free (buf); return -1; } *id_len = sz - ISAKMP_GEN_SZ; *id = malloc (*id_len); if (!*id) { log_error ("ike_phase_1_send_ID: malloc (%lu) failed", (unsigned long)*id_len); return -1; } memcpy (*id, buf + ISAKMP_GEN_SZ, *id_len); snprintf (header, sizeof header, "ike_phase_1_send_ID: %s", constant_name (ipsec_id_cst, GET_ISAKMP_ID_TYPE (buf))); LOG_DBG_BUF ((LOG_NEGOTIATION, 40, header, buf + ISAKMP_ID_DATA_OFF, sz - ISAKMP_ID_DATA_OFF)); return 0; }