Implemented IKEv1 pubkey SIG payload processing in an authenticator
[strongswan.git] / src / libcharon / sa / authenticators / pubkey_v1_authenticator.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "pubkey_v1_authenticator.h"
17
18 #include <daemon.h>
19 #include <sa/keymat_v1.h>
20 #include <encoding/payloads/hash_payload.h>
21
22 typedef struct private_pubkey_v1_authenticator_t private_pubkey_v1_authenticator_t;
23
24 /**
25 * Private data of an pubkey_v1_authenticator_t object.
26 */
27 struct private_pubkey_v1_authenticator_t {
28
29 /**
30 * Public authenticator_t interface.
31 */
32 pubkey_v1_authenticator_t public;
33
34 /**
35 * Assigned IKE_SA
36 */
37 ike_sa_t *ike_sa;
38
39 /**
40 * TRUE if we are initiator
41 */
42 bool initiator;
43
44 /**
45 * DH key exchange
46 */
47 diffie_hellman_t *dh;
48
49 /**
50 * Others DH public value
51 */
52 chunk_t dh_value;
53
54 /**
55 * Encoded SA payload, without fixed header
56 */
57 chunk_t sa_payload;
58 };
59
60 METHOD(authenticator_t, build, status_t,
61 private_pubkey_v1_authenticator_t *this, message_t *message)
62 {
63 hash_payload_t *sig_payload;
64 chunk_t hash, sig, dh;
65 keymat_v1_t *keymat;
66 status_t status;
67 private_key_t *private;
68 identification_t *id;
69 auth_cfg_t *auth;
70 key_type_t type;
71 signature_scheme_t scheme;
72
73 /* TODO-IKEv1: other key types */
74 type = KEY_RSA;
75 scheme = SIGN_RSA_EMSA_PKCS1_NULL;
76
77 id = this->ike_sa->get_my_id(this->ike_sa);
78 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
79 private = lib->credmgr->get_private(lib->credmgr, KEY_RSA, id, auth);
80 if (!private)
81 {
82 DBG1(DBG_IKE, "no private key found for '%Y'", id);
83 return NOT_FOUND;
84 }
85
86 this->dh->get_my_public_value(this->dh, &dh);
87 keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
88 hash = keymat->get_hash(keymat, this->initiator, dh, this->dh_value,
89 this->ike_sa->get_id(this->ike_sa), this->sa_payload, id);
90 free(dh.ptr);
91
92 if (private->sign(private, scheme, hash, &sig))
93 {
94 sig_payload = hash_payload_create(SIGNATURE_V1);
95 sig_payload->set_hash(sig_payload, sig);
96 free(sig.ptr);
97 message->add_payload(message, &sig_payload->payload_interface);
98 status = SUCCESS;
99 DBG1(DBG_IKE, "authentication of '%Y' (myself) successful", id);
100 }
101 else
102 {
103 DBG1(DBG_IKE, "authentication of '%Y' (myself) failed", id);
104 status = FAILED;
105 }
106 private->destroy(private);
107 free(hash.ptr);
108
109 return status;
110 }
111
112 METHOD(authenticator_t, process, status_t,
113 private_pubkey_v1_authenticator_t *this, message_t *message)
114 {
115 chunk_t hash, sig, dh;
116 keymat_v1_t *keymat;
117 public_key_t *public;
118 hash_payload_t *sig_payload;
119 auth_cfg_t *auth, *current_auth;
120 enumerator_t *enumerator;
121 status_t status = NOT_FOUND;
122 key_type_t type;
123 signature_scheme_t scheme;
124 identification_t *id;
125
126 /* TODO-IKEv1: currently RSA only */
127 type = KEY_RSA;
128 scheme = SIGN_RSA_EMSA_PKCS1_NULL;
129
130 sig_payload = (hash_payload_t*)message->get_payload(message, SIGNATURE_V1);
131 if (!sig_payload)
132 {
133 DBG1(DBG_IKE, "SIG payload missing in message");
134 return FALSE;
135 }
136
137 id = this->ike_sa->get_other_id(this->ike_sa);
138 this->dh->get_my_public_value(this->dh, &dh);
139 keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
140 hash = keymat->get_hash(keymat, !this->initiator, this->dh_value, dh,
141 this->ike_sa->get_id(this->ike_sa), this->sa_payload, id);
142 free(dh.ptr);
143
144 sig = sig_payload->get_hash(sig_payload);
145 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
146 enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, type,
147 id, auth);
148 while (enumerator->enumerate(enumerator, &public, &current_auth))
149 {
150 if (public->verify(public, scheme, hash, sig))
151 {
152 DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
153 id, key_type_names, type);
154 status = SUCCESS;
155 auth->merge(auth, current_auth, FALSE);
156 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
157 break;
158 }
159 else
160 {
161 DBG1(DBG_IKE, "signature validation failed, looking for another key");
162 status = FAILED;
163 }
164 }
165 enumerator->destroy(enumerator);
166 free(hash.ptr);
167 if (status != SUCCESS)
168 {
169 DBG1(DBG_IKE, "no trusted %N public key found for '%Y'",
170 key_type_names, type, id);
171 }
172 return status;
173 }
174
175 METHOD(authenticator_t, destroy, void,
176 private_pubkey_v1_authenticator_t *this)
177 {
178 free(this);
179 }
180
181 /*
182 * Described in header.
183 */
184 pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa,
185 bool initiator, diffie_hellman_t *dh,
186 chunk_t dh_value, chunk_t sa_payload)
187 {
188 private_pubkey_v1_authenticator_t *this;
189
190 INIT(this,
191 .public = {
192 .authenticator = {
193 .build = _build,
194 .process = _process,
195 .is_mutual = (void*)return_false,
196 .destroy = _destroy,
197 },
198 },
199 .ike_sa = ike_sa,
200 .initiator = initiator,
201 .dh = dh,
202 .dh_value = dh_value,
203 .sa_payload = sa_payload,
204 );
205
206 return &this->public;
207 }