aboutsummaryrefslogtreecommitdiffstats
path: root/src/pluto/ipsec_doi.c
diff options
context:
space:
mode:
authorAndreas Steffen <andreas.steffen@strongswan.org>2009-06-05 21:14:31 +0200
committerMartin Willi <martin@strongswan.org>2009-06-09 11:03:32 +0200
commit8b799d55ce5b0cf48b6d1dd0c3ca6a1474234ed6 (patch)
tree6933a085f303dd3e232683cbdb9a25b99078b187 /src/pluto/ipsec_doi.c
parentb00fbdb55a1054b35270051722cdcd8c059a337a (diff)
downloadstrongswan-8b799d55ce5b0cf48b6d1dd0c3ca6a1474234ed6.tar.bz2
strongswan-8b799d55ce5b0cf48b6d1dd0c3ca6a1474234ed6.tar.xz
pluto and scepclient use private and public key plugins of libstrongswan
Diffstat (limited to 'src/pluto/ipsec_doi.c')
-rw-r--r--src/pluto/ipsec_doi.c364
1 files changed, 109 insertions, 255 deletions
diff --git a/src/pluto/ipsec_doi.c b/src/pluto/ipsec_doi.c
index 52f5553f0..49f40e38d 100644
--- a/src/pluto/ipsec_doi.c
+++ b/src/pluto/ipsec_doi.c
@@ -34,6 +34,8 @@
#include <crypto/hashers/hasher.h>
#include <crypto/prfs/prf.h>
#include <crypto/rngs/rng.h>
+#include <credentials/keys/private_key.h>
+#include <credentials/keys/public_key.h>
#include "constants.h"
#include "defs.h"
@@ -1402,35 +1404,44 @@ static bool generate_skeyids_iv(struct state *st)
return prf_block_size;
}
-/* Create an RSA signature of a hash.
+/* Create a public key signature of a hash.
* Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2.
* Use PKCS#1 version 1.5 encryption of hash (called
* RSAES-PKCS1-V1_5) in PKCS#2.
*/
-static size_t RSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS],
- const u_char *hash_val, size_t hash_len)
+static size_t sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS],
+ u_char *hash_val, size_t hash_len)
{
size_t sz = 0;
smartcard_t *sc = c->spd.this.sc;
if (sc == NULL) /* no smartcard */
{
- const struct RSA_private_key *k = get_RSA_private_key(c);
+ chunk_t hash, sig;
+ private_key_t *private = get_private_key(c);
- if (k == NULL)
+ if (private == NULL)
+ {
return 0; /* failure: no key to use */
-
- sz = k->pub.k;
+ }
+ sz = private->get_keysize(private);
passert(RSA_MIN_OCTETS <= sz && 4 + hash_len < sz && sz <= RSA_MAX_OCTETS);
- sign_hash(k, hash_val, hash_len, sig_val, sz);
+ hash = chunk_create(hash_val, hash_len);
+ sig = chunk_create(sig_val, sz);
+ if (!private->sign(private, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig))
+ {
+ return 0;
+ }
+ memcpy(sig_val, sig.ptr, sz);
+ free(sig.ptr);
}
else if (sc->valid) /* if valid pin then sign hash on the smartcard */
{
- lock_certs_and_keys("RSA_sign_hash");
+ lock_certs_and_keys("sign_hash");
if (!scx_establish_context(sc) || !scx_login(sc))
{
scx_release_context(sc);
- unlock_certs_and_keys("RSA_sign_hash");
+ unlock_certs_and_keys("sign_hash");
return 0;
}
@@ -1439,7 +1450,7 @@ static size_t RSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS]
{
plog("failed to get keylength from smartcard");
scx_release_context(sc);
- unlock_certs_and_keys("RSA_sign_hash");
+ unlock_certs_and_keys("sign_hash");
return 0;
}
@@ -1450,142 +1461,11 @@ static size_t RSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS]
sz = scx_sign_hash(sc, hash_val, hash_len, sig_val, sz) ? sz : 0;
if (!pkcs11_keep_state)
scx_release_context(sc);
- unlock_certs_and_keys("RSA_sign_hash");
+ unlock_certs_and_keys("sign_hash");
}
return sz;
}
-/* Check a Main Mode RSA Signature against computed hash using RSA public key k.
- *
- * As a side effect, on success, the public key is copied into the
- * state object to record the authenticator.
- *
- * Can fail because wrong public key is used or because hash disagrees.
- * We distinguish because diagnostics should also.
- *
- * The result is NULL if the Signature checked out.
- * Otherwise, the first character of the result indicates
- * how far along failure occurred. A greater character signifies
- * greater progress.
- *
- * Classes:
- * 0 reserved for caller
- * 1 SIG length doesn't match key length -- wrong key
- * 2-8 malformed ECB after decryption -- probably wrong key
- * 9 decrypted hash != computed hash -- probably correct key
- *
- * Although the math should be the same for generating and checking signatures,
- * it is not: the knowledge of the private key allows more efficient (i.e.
- * different) computation for encryption.
- */
-static err_t try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN],
- size_t hash_len, const pb_stream *sig_pbs,
- pubkey_t *kr, struct state *st)
-{
- const u_char *sig_val = sig_pbs->cur;
- size_t sig_len = pbs_left(sig_pbs);
- u_char s[RSA_MAX_OCTETS]; /* for decrypted sig_val */
- u_char *hash_in_s = &s[sig_len - hash_len];
- const struct RSA_public_key *k = &kr->u.rsa;
-
- /* decrypt the signature -- reversing RSA_sign_hash */
- if (sig_len != k->k)
- {
- /* XXX notification: INVALID_KEY_INFORMATION */
- return "1" "SIG length does not match public key length";
- }
-
- /* actual exponentiation; see PKCS#1 v2.0 5.1 */
- {
- chunk_t temp_s;
- mpz_t c;
-
- n_to_mpz(c, sig_val, sig_len);
- mpz_powm(c, c, &k->e, &k->n);
-
- temp_s = mpz_to_n(c, sig_len); /* back to octets */
- memcpy(s, temp_s.ptr, sig_len);
- free(temp_s.ptr);
- mpz_clear(c);
- }
-
- /* sanity check on signature: see if it matches
- * PKCS#1 v1.5 8.1 encryption-block formatting
- */
- {
- err_t ugh = NULL;
-
- if (s[0] != 0x00)
- ugh = "2" "no leading 00";
- else if (hash_in_s[-1] != 0x00)
- ugh = "3" "00 separator not present";
- else if (s[1] == 0x01)
- {
- const u_char *p;
-
- for (p = &s[2]; p != hash_in_s - 1; p++)
- {
- if (*p != 0xFF)
- {
- ugh = "4" "invalid Padding String";
- break;
- }
- }
- }
- else if (s[1] == 0x02)
- {
- const u_char *p;
-
- for (p = &s[2]; p != hash_in_s - 1; p++)
- {
- if (*p == 0x00)
- {
- ugh = "5" "invalid Padding String";
- break;
- }
- }
- }
- else
- ugh = "6" "Block Type not 01 or 02";
-
- if (ugh != NULL)
- {
- /* note: it might be a good idea to make sure that
- * an observer cannot tell what kind of failure happened.
- * I don't know what this means in practice.
- */
- /* We probably selected the wrong public key for peer:
- * SIG Payload decrypted into malformed ECB
- */
- /* XXX notification: INVALID_KEY_INFORMATION */
- return ugh;
- }
- }
-
- /* We have the decoded hash: see if it matches. */
- if (memcmp(hash_val, hash_in_s, hash_len) != 0)
- {
- /* good: header, hash, signature, and other payloads well-formed
- * good: we could find an RSA Sig key for the peer.
- * bad: hash doesn't match
- * Guess: sides disagree about key to be used.
- */
- DBG_cond_dump(DBG_CRYPT, "decrypted SIG", s, sig_len);
- DBG_cond_dump(DBG_CRYPT, "computed HASH", hash_val, hash_len);
- /* XXX notification: INVALID_HASH_INFORMATION */
- return "9" "authentication failure: received SIG does not match computed HASH, but message is well-formed";
- }
-
- /* Success: copy successful key into state.
- * There might be an old one if we previously aborted this
- * state transition.
- */
- unreference_key(&st->st_peer_pubkey);
- st->st_peer_pubkey = reference_key(kr);
-
- return NULL; /* happy happy */
-}
-
/* Check signature against all RSA public keys we can find.
* If we need keys from DNS KEY records, and they haven't been fetched,
* return STF_SUSPEND to ask for asynch DNS lookup.
@@ -1597,54 +1477,39 @@ static err_t try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN],
* If only we had coroutines.
*/
struct tac_state {
- /* RSA_check_signature's args that take_a_crack needs */
struct state *st;
- const u_char *hash_val;
- size_t hash_len;
- const pb_stream *sig_pbs;
-
- /* state carried between calls */
- err_t best_ugh; /* most successful failure */
+ chunk_t hash;
+ chunk_t sig;
int tried_cnt; /* number of keys tried */
- char tried[50]; /* keyids of tried public keys */
- char *tn; /* roof of tried[] */
};
-static bool take_a_crack(struct tac_state *s, pubkey_t *kr,
- const char *story USED_BY_DEBUG)
+static bool take_a_crack(struct tac_state *s, pubkey_t *kr)
{
- err_t ugh = try_RSA_signature(s->hash_val, s->hash_len, s->sig_pbs
- , kr, s->st);
- const struct RSA_public_key *k = &kr->u.rsa;
+ public_key_t *pub_key = kr->public_key;
+ identification_t *keyid = pub_key->get_id(pub_key, ID_PUBKEY_SHA1);
s->tried_cnt++;
- if (ugh == NULL)
+
+ if (pub_key->verify(pub_key, SIGN_RSA_EMSA_PKCS1_NULL, s->hash, s->sig))
{
- DBG(DBG_CRYPT | DBG_CONTROL
- , DBG_log("an RSA Sig check passed with *%s [%s]"
- , k->keyid, story));
+ DBG(DBG_CRYPT | DBG_CONTROL,
+ DBG_log("signature check passed with keyid %Y", keyid)
+ )
+ unreference_key(&s->st->st_peer_pubkey);
+ s->st->st_peer_pubkey = reference_key(kr);
return TRUE;
}
else
{
- DBG(DBG_CRYPT
- , DBG_log("an RSA Sig check failure %s with *%s [%s]"
- , ugh + 1, k->keyid, story));
- if (s->best_ugh == NULL || s->best_ugh[0] < ugh[0])
- s->best_ugh = ugh;
- if (ugh[0] > '0'
- && s->tn - s->tried + KEYID_BUF + 2 < (ptrdiff_t)sizeof(s->tried))
- {
- strcpy(s->tn, " *");
- strcpy(s->tn + 2, k->keyid);
- s->tn += strlen(s->tn);
- }
+ DBG(DBG_CRYPT,
+ DBG_log("signature check failed with keyid %Y", keyid)
+ )
return FALSE;
}
}
static stf_status RSA_check_signature(const struct id* peer, struct state *st,
- const u_char hash_val[MAX_DIGEST_LEN],
+ u_char hash_val[MAX_DIGEST_LEN],
size_t hash_len, const pb_stream *sig_pbs,
#ifdef USE_KEYRR
const pubkey_list_t *keys_from_dns,
@@ -1653,16 +1518,11 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
{
const struct connection *c = st->st_connection;
struct tac_state s;
- err_t dns_ugh = NULL;
s.st = st;
- s.hash_val = hash_val;
- s.hash_len = hash_len;
- s.sig_pbs = sig_pbs;
-
- s.best_ugh = NULL;
+ s.hash = chunk_create(hash_val, hash_len);
+ s.sig = chunk_create(sig_pbs->cur, pbs_left(sig_pbs));
s.tried_cnt = 0;
- s.tn = s.tried;
/* try all gateway records hung off c */
if (c->policy & POLICY_OPPO)
@@ -1672,10 +1532,11 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
for (gw = c->gw_info; gw != NULL; gw = gw->next)
{
/* only consider entries that have a key and are for our peer */
- if (gw->gw_key_present
- && same_id(&gw->gw_id, &c->spd.that.id)
- && take_a_crack(&s, gw->key, "key saved from DNS TXT"))
+ if (gw->gw_key_present && same_id(&gw->gw_id, &c->spd.that.id)&&
+ take_a_crack(&s, gw->key))
+ {
return STF_OK;
+ }
}
}
@@ -1688,8 +1549,9 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
for (p = pubkeys; p != NULL; p = *pp)
{
pubkey_t *key = p->key;
+ key_type_t type = key->public_key->get_type(key->public_key);
- if (key->alg == PUBKEY_ALG_RSA && same_id(peer, &key->id))
+ if (type == KEY_RSA && same_id(peer, &key->id))
{
time_t now = time(NULL);
@@ -1702,18 +1564,19 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
continue; /* continue with next public key */
}
- if (take_a_crack(&s, key, "preloaded key"))
- return STF_OK;
+ if (take_a_crack(&s, key))
+ {
+ return STF_OK;
+ }
}
pp = &p->next;
}
}
- /* if no key was found (evidenced by best_ugh == NULL)
- * and that side of connection is key_from_DNS_on_demand
- * then go search DNS for keys for peer.
+ /* if no key was found and that side of connection is
+ * key_from_DNS_on_demand then go search DNS for keys for peer.
*/
- if (s.best_ugh == NULL && c->spd.that.key_from_DNS_on_demand)
+ if (s.tried_cnt == 0 && c->spd.that.key_from_DNS_on_demand)
{
if (gateways_from_dns != NULL)
{
@@ -1721,9 +1584,12 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
const struct gw_info *gwp;
for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next)
- if (gwp->gw_key_present
- && take_a_crack(&s, gwp->key, "key from DNS TXT"))
+ {
+ if (gwp->gw_key_present && take_a_crack(&s, gwp->key))
+ {
return STF_OK;
+ }
+ }
}
#ifdef USE_KEYRR
else if (keys_from_dns != NULL)
@@ -1732,9 +1598,12 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
const pubkey_list_t *kr;
for (kr = keys_from_dns; kr != NULL; kr = kr->next)
- if (kr->key->alg == PUBKEY_ALG_RSA
- && take_a_crack(&s, kr->key, "key from DNS KEY"))
+ {
+ if (kr->key->alg == PUBKEY_ALG_RSA && take_a_crack(&s, kr->key))
+ {
return STF_OK;
+ }
+ }
}
#endif /* USE_KEYRR */
else
@@ -1748,53 +1617,32 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
{
char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */
- (void) idtoa(peer, id_buf, sizeof(id_buf));
+ idtoa(peer, id_buf, sizeof(id_buf));
- if (s.best_ugh == NULL)
+ if (s.tried_cnt == 0)
{
- if (dns_ugh == NULL)
- loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'"
- , id_buf);
- else
- loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'"
- "; DNS search for KEY failed (%s)"
- , id_buf, dns_ugh);
-
- /* ??? is this the best code there is? */
- return STF_FAIL + INVALID_KEY_INFORMATION;
+ loglog(RC_LOG_SERIOUS, "no public key known for '%s'", id_buf);
}
-
- if (s.best_ugh[0] == '9')
+ else if (s.tried_cnt == 1)
{
- loglog(RC_LOG_SERIOUS, "%s", s.best_ugh + 1);
- /* XXX Could send notification back */
- return STF_FAIL + INVALID_HASH_INFORMATION;
+ loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: "
+ " wrong key?; tried %d", id_buf, s.tried_cnt);
+ DBG(DBG_CONTROL,
+ DBG_log("public key for '%s' failed: "
+ "decrypted SIG payload into a malformed ECB", id_buf)
+ )
}
else
{
- if (s.tried_cnt == 1)
- {
- loglog(RC_LOG_SERIOUS
- , "Signature check (on %s) failed (wrong key?); tried%s"
- , id_buf, s.tried);
- DBG(DBG_CONTROL,
- DBG_log("public key for %s failed:"
- " decrypted SIG payload into a malformed ECB (%s)"
- , id_buf, s.best_ugh + 1));
- }
- else
- {
- loglog(RC_LOG_SERIOUS
- , "Signature check (on %s) failed:"
- " tried%s keys but none worked."
- , id_buf, s.tried);
- DBG(DBG_CONTROL,
- DBG_log("all %d public keys for %s failed:"
- " best decrypted SIG payload into a malformed ECB (%s)"
- , s.tried_cnt, id_buf, s.best_ugh + 1));
- }
- return STF_FAIL + INVALID_KEY_INFORMATION;
+ loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: "
+ "tried %d keys but none worked.", id_buf, s.tried_cnt);
+ DBG(DBG_CONTROL,
+ DBG_log("all %d public keys for '%s' failed: "
+ "best decrypted SIG payload into a malformed ECB",
+ s.tried_cnt, id_buf)
+ )
}
+ return STF_FAIL + INVALID_KEY_INFORMATION;
}
}
@@ -2245,6 +2093,7 @@ static void decode_cert(struct msg_digest *md)
{
plog("X.509 certificate rejected");
}
+ DESTROY_IF(cert.public_key);
free_generalNames(cert.subjectAltName, FALSE);
free_generalNames(cert.crlDistributionPoints, FALSE);
}
@@ -2749,9 +2598,9 @@ static bool has_preloaded_public_key(struct state *st)
for (p = pubkeys; p != NULL; p = p->next)
{
pubkey_t *key = p->key;
+ key_type_t type = key->public_key->get_type(key->public_key);
- if (key->alg == PUBKEY_ALG_RSA &&
- same_id(&c->spd.that.id, &key->id) &&
+ if (type == KEY_RSA && same_id(&c->spd.that.id, &key->id) &&
key->until_time == UNDEFINED_TIME)
{
/* found a preloaded public key */
@@ -3595,12 +3444,12 @@ stf_status main_inR2_outI3(struct msg_digest *md)
{
/* SIG_I out */
u_char sig_val[RSA_MAX_OCTETS];
- size_t sig_len = RSA_sign_hash(st->st_connection
- , sig_val, hash_val, hash_len);
+ size_t sig_len = sign_hash(st->st_connection, sig_val, hash_val,
+ hash_len);
if (sig_len == 0)
{
- loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
+ loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature");
return STF_FAIL + AUTHENTICATION_FAILED;
}
@@ -3997,12 +3846,12 @@ main_inI3_outR3_tail(struct msg_digest *md
{
/* SIG_R out */
u_char sig_val[RSA_MAX_OCTETS];
- size_t sig_len = RSA_sign_hash(st->st_connection
- , sig_val, hash_val, hash_len);
+ size_t sig_len = sign_hash(st->st_connection, sig_val, hash_val,
+ hash_len);
if (sig_len == 0)
{
- loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
+ loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature");
return STF_FAIL + AUTHENTICATION_FAILED;
}
@@ -4479,10 +4328,10 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_our_client:
next_step = vos_his_client;
{
- const struct RSA_private_key *pri = get_RSA_private_key(c);
+ private_key_t *private = get_private_key(c);
struct gw_info *gwp;
- if (pri == NULL)
+ if (private == NULL)
{
ugh = "we don't know our own key";
break;
@@ -4503,7 +4352,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
ugh = NULL; /* good! */
break;
}
- else if (same_RSA_public_key(&pri->pub, &gwp->key->u.rsa))
+ else if (private->belongs_to(private, gwp->key->public_key))
{
ugh = NULL; /* good! */
break;
@@ -4515,9 +4364,9 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_our_txt:
next_step = vos_his_client;
{
- const struct RSA_private_key *pri = get_RSA_private_key(c);
+ private_key_t *private = get_private_key(c);
- if (pri == NULL)
+ if (private == NULL)
{
ugh = "we don't know our own key";
break;
@@ -4534,7 +4383,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";
#endif
if (gwp->gw_key_present
- && same_RSA_public_key(&pri->pub, &gwp->key->u.rsa))
+ && private->belongs_to(private, gwp->key->public_key))
{
ugh = NULL; /* good! */
break;
@@ -4551,9 +4400,9 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_our_key:
next_step = vos_his_client;
{
- const struct RSA_private_key *pri = get_RSA_private_key(c);
+ private_key_t *private = get_private_key(c);
- if (pri == NULL)
+ if (private == NULL)
{
ugh = "we don't know our own key";
break;
@@ -4565,7 +4414,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
for (kp = ac->keys_from_dns; kp != NULL; kp = kp->next)
{
ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";
- if (same_RSA_public_key(&pri->pub, &kp->key->u.rsa))
+ if (private->belongs_to(private, kp->key->public_key))
{
/* do this only once a day */
if (!logged_txt_warning)
@@ -4585,11 +4434,15 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_his_client:
next_step = vos_done;
{
+ public_key_t *pub_key;
+ identification_t *p1st_keyid;
struct gw_info *gwp;
-
+
/* check that the public key that authenticated
* the ISAKMP SA (p1st) will do for this gateway.
*/
+ pub_key = p1st->st_peer_pubkey->public_key;
+ p1st_keyid = pub_key->get_id(pub_key, ID_PUBKEY_INFO_SHA1);
ugh = "peer's client does not delegate to peer";
for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
@@ -4601,9 +4454,10 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
* it implies fetching a KEY from the same
* place we must have gotten it.
*/
- if (!gwp->gw_key_present
- || same_RSA_public_key(&p1st->st_peer_pubkey->u.rsa
- , &gwp->key->u.rsa))
+ if (!gwp->gw_key_present || p1st_keyid->equals(p1st_keyid,
+ gwp->key->public_key->get_id(gwp->key->public_key,
+ ID_PUBKEY_INFO_SHA1))
+ )
{
ugh = NULL; /* good! */
break;