/* Release a reference to SA. */ void sa_release(struct sa *sa) { struct cert_handler *handler; struct proto *proto; LOG_DBG((LOG_SA, 80, "sa_release: SA %p had %d references", sa, sa->refcnt)); if (--sa->refcnt) return; LOG_DBG((LOG_SA, 60, "sa_release: freeing SA %p", sa)); while ((proto = TAILQ_FIRST(&sa->protos)) != 0) proto_free(proto); if (sa->data) { if (sa->doi && sa->doi->free_sa_data) sa->doi->free_sa_data(sa->data); free(sa->data); } free(sa->id_i); free(sa->id_r); if (sa->recv_cert) { handler = cert_get(sa->recv_certtype); if (handler) handler->cert_free(sa->recv_cert); } if (sa->sent_cert) { handler = cert_get(sa->sent_certtype); if (handler) handler->cert_free(sa->sent_cert); } if (sa->recv_key) key_free(sa->recv_keytype, ISAKMP_KEYTYPE_PUBLIC, sa->recv_key); free(sa->keynote_key); /* This is just a string */ if (sa->policy_id != -1) kn_close(sa->policy_id); free(sa->name); free(sa->keystate); if (sa->nat_t_keepalive) timer_remove_event(sa->nat_t_keepalive); if (sa->dpd_event) timer_remove_event(sa->dpd_event); if (sa->transport) transport_release(sa->transport); free(sa->tag); free(sa); }
/* * Decode the certificate request of type TYPE contained in DATA extending * DATALEN bytes. Return a certreq_aca structure which the caller is * responsible for deallocating. */ struct certreq_aca * certreq_decode(u_int16_t type, u_int8_t *data, u_int32_t datalen) { struct cert_handler *handler; struct certreq_aca aca, *ret; handler = cert_get(type); if (!handler) return 0; aca.id = type; aca.handler = handler; aca.data = aca.raw_ca = NULL; if (datalen > 0) { int rc; rc = handler->certreq_decode(&aca.data, data, datalen); if (!rc) return 0; aca.raw_ca = malloc(datalen); if (aca.raw_ca == NULL) { log_error("certreq_decode: malloc (%lu) failed", (unsigned long)datalen); handler->free_aca(aca.data); return 0; } memcpy(aca.raw_ca, data, datalen); } aca.raw_ca_len = datalen; ret = malloc(sizeof aca); if (!ret) { log_error("certreq_decode: malloc (%lu) failed", (unsigned long)sizeof aca); free(aca.raw_ca); handler->free_aca(aca.data); return 0; } memcpy(ret, &aca, sizeof aca); return ret; }
/* Encrypt the HASH into a SIG type. */ static int rsa_sig_encode_hash (struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; size_t hashsize = ie->hash->hashsize; struct cert_handler *handler; char header[80]; int initiator = exchange->initiator; u_int8_t *buf, *data, *buf2; u_int32_t datalen; u_int8_t *id; size_t id_len; int idtype; void *sent_key; id = initiator ? exchange->id_i : exchange->id_r; id_len = initiator ? exchange->id_i_len : exchange->id_r_len; /* We may have been provided these by the kernel */ buf = (u_int8_t *)conf_get_str (exchange->name, "Credentials"); if (buf && (idtype = conf_get_num (exchange->name, "Credential_Type", -1) != -1)) { exchange->sent_certtype = idtype; handler = cert_get (idtype); if (!handler) { log_print ("rsa_sig_encode_hash: cert_get (%d) failed", idtype); return -1; } exchange->sent_cert = handler->cert_from_printable ((char *)buf); if (!exchange->sent_cert) { log_print ("rsa_sig_encode_hash: failed to retrieve certificate"); return -1; } handler->cert_serialize (exchange->sent_cert, &data, &datalen); if (!data) { log_print ("rsa_sig_encode_hash: cert serialization failed"); return -1; } goto aftercert; /* Skip all the certificate discovery */ } /* XXX This needs to be configurable. */ idtype = ISAKMP_CERTENC_KEYNOTE; /* Find a certificate with subjectAltName = id. */ handler = cert_get (idtype); if (!handler) { idtype = ISAKMP_CERTENC_X509_SIG; handler = cert_get (idtype); if (!handler) { log_print ("rsa_sig_encode_hash: cert_get(%d) failed", idtype); return -1; } } if (handler->cert_obtain (id, id_len, 0, &data, &datalen) == 0) { if (idtype == ISAKMP_CERTENC_KEYNOTE) { idtype = ISAKMP_CERTENC_X509_SIG; handler = cert_get (idtype); if (!handler) { log_print ("rsa_sig_encode_hash: cert_get(%d) failed", idtype); return -1; } if (handler->cert_obtain (id, id_len, 0, &data, &datalen) == 0) { LOG_DBG ((LOG_MISC, 10, "rsa_sig_encode_hash: no certificate to send")); goto skipcert; } } else { LOG_DBG ((LOG_MISC, 10, "rsa_sig_encode_hash: no certificate to send")); goto skipcert; } } /* Let's store the certificate we are going to use */ exchange->sent_certtype = idtype; exchange->sent_cert = handler->cert_get (data, datalen); if (!exchange->sent_cert) { free (data); log_print ("rsa_sig_encode_hash: failed to get certificate from wire " "encoding"); return -1; } aftercert: buf = realloc (data, ISAKMP_CERT_SZ + datalen); if (!buf) { log_error ("rsa_sig_encode_hash: realloc (%p, %d) failed", data, ISAKMP_CERT_SZ + datalen); free (data); return -1; } memmove (buf + ISAKMP_CERT_SZ, buf, datalen); SET_ISAKMP_CERT_ENCODING (buf, idtype); if (message_add_payload (msg, ISAKMP_PAYLOAD_CERT, buf, ISAKMP_CERT_SZ + datalen, 1)) { free (buf); return -1; } skipcert: /* Again, we may have these from the kernel */ buf = (u_int8_t *)conf_get_str (exchange->name, "PKAuthentication"); if (buf) { key_from_printable (ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, (char *)buf, &data, &datalen); if (!data || datalen == -1) { log_print ("rsa_sig_encode_hash: badly formatted RSA private key"); return 0; } sent_key = key_internalize (ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, data, datalen); if (!sent_key) { log_print ("rsa_sig_encode_hash: bad RSA private key from dynamic " "SA acquisition subsystem"); return 0; } #if defined (USE_PRIVSEP) { /* With USE_PRIVSEP, the sent_key should be a key number. */ void *key = sent_key; sent_key = monitor_RSA_upload_key (key); } #endif } else /* Try through the regular means. */ { switch (id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ]) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: util_ntoa ((char **)&buf2, id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ] == IPSEC_ID_IPV4_ADDR ? AF_INET : AF_INET6, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ); if (!buf2) return 0; break; case IPSEC_ID_FQDN: case IPSEC_ID_USER_FQDN: buf2 = calloc (id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1, sizeof (char)); if (!buf2) { log_print ("rsa_sig_encode_hash: malloc (%lu) failed", (unsigned long)id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1); return 0; } memcpy (buf2, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ); break; /* XXX Support more ID types? */ default: buf2 = 0; return 0; } #if defined (USE_PRIVSEP) sent_key = monitor_RSA_get_private_key (exchange->name, (char *)buf2); #else sent_key = ike_auth_get_key (IKE_AUTH_RSA_SIG, exchange->name, (char *)buf2, 0); #endif free (buf2); /* Did we find a key? */ if (!sent_key) { log_print ("rsa_sig_encode_hash: could not get private key"); return -1; } } #if !defined (USE_PRIVSEP) /* Enable RSA blinding. */ if (RSA_blinding_on (sent_key, NULL) != 1) { log_error ("rsa_sig_encode_hash: RSA_blinding_on () failed."); return -1; } #endif /* XXX hashsize is not necessarily prf->blocksize. */ buf = malloc (hashsize); if (!buf) { log_error ("rsa_sig_encode_hash: malloc (%lu) failed", (unsigned long)hashsize); return -1; } if (ike_auth_hash (exchange, buf) == -1) { free (buf); return -1; } snprintf (header, sizeof header, "rsa_sig_encode_hash: HASH_%c", initiator ? 'I' : 'R'); LOG_DBG_BUF ((LOG_MISC, 80, header, buf, hashsize)); #if !defined (USE_PRIVSEP) data = malloc (RSA_size (sent_key)); if (!data) { log_error ("rsa_sig_encode_hash: malloc (%d) failed", RSA_size (sent_key)); return -1; } datalen = RSA_private_encrypt (hashsize, buf, data, sent_key, RSA_PKCS1_PADDING); #else datalen = monitor_RSA_private_encrypt (hashsize, buf, &data, sent_key, RSA_PKCS1_PADDING); #endif /* USE_PRIVSEP */ if (datalen == -1) { log_print ("rsa_sig_encode_hash: RSA_private_encrypt () failed"); if (data) free (data); free (buf); monitor_RSA_free (sent_key); return -1; } free (buf); buf = realloc (data, ISAKMP_SIG_SZ + datalen); if (!buf) { log_error ("rsa_sig_encode_hash: realloc (%p, %d) failed", data, ISAKMP_SIG_SZ + datalen); free (data); return -1; } memmove (buf + ISAKMP_SIG_SZ, buf, datalen); snprintf (header, sizeof header, "rsa_sig_encode_hash: SIG_%c", initiator ? 'I' : 'R'); LOG_DBG_BUF ((LOG_MISC, 80, header, buf + ISAKMP_SIG_DATA_OFF, datalen)); if (message_add_payload (msg, ISAKMP_PAYLOAD_SIG, buf, ISAKMP_SIG_SZ + datalen, 1)) { free (buf); return -1; } return 0; }
/* Decrypt the HASH in SIG, we already need a parsed ID payload. */ static int rsa_sig_decode_hash (struct message *msg) { struct cert_handler *handler; struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct payload *p; void *cert = 0; u_int8_t *rawcert = 0; u_int32_t rawcertlen; RSA *key = 0; size_t hashsize = ie->hash->hashsize; char header[80]; int len; int initiator = exchange->initiator; u_int8_t **hash_p, **id_cert, *id; u_int32_t *id_cert_len; size_t id_len; int found = 0, n, i, id_found; #if defined (USE_DNSSEC) u_int8_t *rawkey = 0; u_int32_t rawkeylen; #endif /* Choose the right fields to fill-in. */ hash_p = initiator ? &ie->hash_r : &ie->hash_i; id = initiator ? exchange->id_r : exchange->id_i; id_len = initiator ? exchange->id_r_len : exchange->id_i_len; if (!id || id_len == 0) { log_print ("rsa_sig_decode_hash: ID is missing"); return -1; } /* * XXX Assume we should use the same kind of certification as the remote... * moreover, just use the first CERT payload to decide what to use. */ p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_CERT]); if (!p) handler = cert_get (ISAKMP_CERTENC_KEYNOTE); else handler = cert_get (GET_ISAKMP_CERT_ENCODING (p->p)); if (!handler) { log_print ("rsa_sig_decode_hash: cert_get (%d) failed", p ? GET_ISAKMP_CERT_ENCODING (p->p) : -1); return -1; } #if defined (USE_POLICY) && defined (USE_KEYNOTE) /* * We need the policy session initialized now, so we can add * credentials etc. */ exchange->policy_id = kn_init (); if (exchange->policy_id == -1) { log_print ("rsa_sig_decode_hash: failed to initialize policy session"); return -1; } #endif /* USE_POLICY || USE_KEYNOTE */ /* Obtain a certificate from our certificate storage. */ if (handler->cert_obtain (id, id_len, 0, &rawcert, &rawcertlen)) { if (handler->id == ISAKMP_CERTENC_X509_SIG) { cert = handler->cert_get (rawcert, rawcertlen); if (!cert) LOG_DBG ((LOG_CRYPTO, 50, "rsa_sig_decode_hash: certificate malformed")); else { if (!handler->cert_get_key (cert, &key)) { log_print ("rsa_sig_decode_hash: " "decoding certificate failed"); handler->cert_free (cert); } else { found++; LOG_DBG ((LOG_CRYPTO, 40, "rsa_sig_decode_hash: using cert of type %d", handler->id)); exchange->recv_cert = cert; exchange->recv_certtype = handler->id; #if defined (USE_POLICY) x509_generate_kn (exchange->policy_id, cert); #endif /* USE_POLICY */ } } } else if (handler->id == ISAKMP_CERTENC_KEYNOTE) handler->cert_insert (exchange->policy_id, rawcert); free (rawcert); } /* * Walk over potential CERT payloads in this message. * XXX I believe this is the wrong spot for this. CERTs can appear * anytime. */ for (p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_CERT]); p; p = TAILQ_NEXT (p, link)) { p->flags |= PL_MARK; /* When we have found a key, just walk over the rest, marking them. */ if (found) continue; handler = cert_get (GET_ISAKMP_CERT_ENCODING (p->p)); if (!handler) { LOG_DBG ((LOG_MISC, 30, "rsa_sig_decode_hash: no handler for %s CERT encoding", constant_name (isakmp_certenc_cst, GET_ISAKMP_CERT_ENCODING (p->p)))); continue; } cert = handler->cert_get (p->p + ISAKMP_CERT_DATA_OFF, GET_ISAKMP_GEN_LENGTH (p->p) - ISAKMP_CERT_DATA_OFF); if (!cert) { log_print ("rsa_sig_decode_hash: can not get data from CERT"); continue; } if (!handler->cert_validate (cert)) { handler->cert_free (cert); log_print ("rsa_sig_decode_hash: received CERT can't be validated"); continue; } if (GET_ISAKMP_CERT_ENCODING (p->p) == ISAKMP_CERTENC_X509_SIG) { if (!handler->cert_get_subjects (cert, &n, &id_cert, &id_cert_len)) { handler->cert_free (cert); log_print ("rsa_sig_decode_hash: can not get subject from CERT"); continue; } id_found = 0; for (i = 0; i < n; i++) if (id_cert_len[i] == id_len && id[0] == id_cert[i][0] && memcmp (id + 4, id_cert[i] + 4, id_len - 4) == 0) { id_found++; break; } if (!id_found) { handler->cert_free (cert); log_print ("rsa_sig_decode_hash: no CERT subject match the ID"); free (id_cert); continue; } cert_free_subjects (n, id_cert, id_cert_len); } if (!handler->cert_get_key (cert, &key)) { handler->cert_free (cert); log_print ("rsa_sig_decode_hash: decoding payload CERT failed"); continue; } /* We validated the cert, cache it for later use. */ handler->cert_insert (exchange->policy_id, cert); exchange->recv_cert = cert; exchange->recv_certtype = GET_ISAKMP_CERT_ENCODING (p->p); #if defined (USE_POLICY) && defined (USE_KEYNOTE) if (exchange->recv_certtype == ISAKMP_CERTENC_KEYNOTE) { struct keynote_deckey dc; char *pp; int dclen; dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA; dc.dec_key = key; pp = kn_encode_key (&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX, KEYNOTE_PUBLIC_KEY); if (pp == NULL) { kn_free_key (&dc); log_print ("rsa_sig_decode_hash: failed to ASCII-encode key"); return -1; } dclen = strlen (pp) + sizeof "rsa-hex:"; exchange->keynote_key = calloc (dclen, sizeof (char)); if (!exchange->keynote_key) { free (pp); kn_free_key (&dc); log_print ("rsa_sig_decode_hash: failed to allocate %d bytes", dclen); return -1; } snprintf (exchange->keynote_key, dclen, "rsa-hex:%s", pp); free (pp); } #endif found++; } #if defined (USE_DNSSEC) /* If no certificate provided a key, try to find a validated DNSSEC KEY. */ if (!found) { rawkey = dns_get_key (IKE_AUTH_RSA_SIG, msg, &rawkeylen); /* We need to convert 'void *rawkey' into 'RSA *key'. */ if (dns_RSA_dns_to_x509 (rawkey, rawkeylen, &key) == 0) found++; else log_print ("rsa_sig_decode_hash: KEY to RSA key conversion failed"); if (rawkey) free (rawkey); } #endif /* USE_DNSSEC */ #if defined (USE_RAWKEY) /* If we still have not found a key, try to read it from a file. */ if (!found) if (get_raw_key_from_file (IKE_AUTH_RSA_SIG, id, id_len, &key) != -1) found++; #endif if (!found) { log_print ("rsa_sig_decode_hash: no public key found"); return -1; } p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SIG]); if (!p) { log_print ("rsa_sig_decode_hash: missing signature payload"); RSA_free (key); return -1; } /* Check that the sig is of the correct size. */ len = GET_ISAKMP_GEN_LENGTH (p->p) - ISAKMP_SIG_SZ; if (len != RSA_size (key)) { RSA_free (key); log_print ("rsa_sig_decode_hash: " "SIG payload length does not match public key"); return -1; } *hash_p = malloc (len); if (!*hash_p) { RSA_free (key); log_error ("rsa_sig_decode_hash: malloc (%d) failed", len); return -1; } len = RSA_public_decrypt (len, p->p + ISAKMP_SIG_DATA_OFF, *hash_p, key, RSA_PKCS1_PADDING); if (len == -1) { RSA_free (key); log_print ("rsa_sig_decode_hash: RSA_public_decrypt () failed"); return -1; } /* Store key for later use */ exchange->recv_key = key; exchange->recv_keytype = ISAKMP_KEY_RSA; if (len != hashsize) { free (*hash_p); *hash_p = 0; log_print ("rsa_sig_decode_hash: len %lu != hashsize %lu", (unsigned long)len, (unsigned long)hashsize); return -1; } snprintf (header, sizeof header, "rsa_sig_decode_hash: HASH_%c", initiator ? 'R' : 'I'); LOG_DBG_BUF ((LOG_MISC, 80, header, *hash_p, hashsize)); p->flags |= PL_MARK; return 0; }