5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "silcincludes.h"
25 /******************************************************************************
27 Authentication Payload
29 ******************************************************************************/
31 /* Authentication Payload structure */
32 struct SilcAuthPayloadStruct {
36 unsigned char *random_data;
38 unsigned char *auth_data;
41 /* Parses and returns Authentication Payload */
43 SilcAuthPayload silc_auth_payload_parse(const unsigned char *data,
46 SilcBufferStruct buffer;
50 SILC_LOG_DEBUG(("Parsing Authentication Payload"));
52 silc_buffer_set(&buffer, (unsigned char *)data, data_len);
53 new = silc_calloc(1, sizeof(*new));
55 /* Parse the payload */
56 ret = silc_buffer_unformat(&buffer,
57 SILC_STR_UI_SHORT(&new->len),
58 SILC_STR_UI_SHORT(&new->auth_method),
59 SILC_STR_UI16_NSTRING_ALLOC(&new->random_data,
61 SILC_STR_UI16_NSTRING_ALLOC(&new->auth_data,
69 if (new->len != buffer.len) {
70 silc_auth_payload_free(new);
74 /* If password authentication, random data must not be set */
75 if (new->auth_method == SILC_AUTH_PASSWORD && new->random_len) {
76 silc_auth_payload_free(new);
83 /* Encodes authentication payload into buffer and returns it */
85 SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
86 const unsigned char *random_data,
88 const unsigned char *auth_data,
94 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
96 len = 2 + 2 + 2 + random_len + 2 + auth_len;
97 buffer = silc_buffer_alloc(len);
98 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
99 silc_buffer_format(buffer,
100 SILC_STR_UI_SHORT(len),
101 SILC_STR_UI_SHORT(method),
102 SILC_STR_UI_SHORT(random_len),
103 SILC_STR_UI_XNSTRING(random_data, random_len),
104 SILC_STR_UI_SHORT(auth_len),
105 SILC_STR_UI_XNSTRING(auth_data, auth_len),
111 /* Frees authentication payload. */
113 void silc_auth_payload_free(SilcAuthPayload payload)
116 if (payload->random_data) {
117 memset(payload->random_data, 0, payload->random_len);
118 silc_free(payload->random_data);
120 if (payload->auth_data) {
121 memset(payload->auth_data, 0, payload->auth_len);
122 silc_free(payload->auth_data);
128 /* Get authentication method */
130 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
132 return payload->auth_method;
135 /* Get the authentication data */
137 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
141 *auth_len = payload->auth_len;
143 return payload->auth_data;
146 /******************************************************************************
148 Authentication Routines
150 ******************************************************************************/
152 /* Encodes the authentication data for hashing and signing as the protocol
155 static unsigned char *
156 silc_auth_public_key_encode_data(SilcPublicKey public_key,
157 const unsigned char *random,
158 uint32 random_len, const void *id,
159 SilcIdType type, uint32 *ret_len)
162 unsigned char *pk, *id_data, *ret;
163 uint32 pk_len, id_len;
165 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
169 id_data = silc_id_id2str(id, type);
174 id_len = silc_id_get_len(id, type);
176 buf = silc_buffer_alloc(random_len + id_len + pk_len);
177 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
178 silc_buffer_format(buf,
179 SILC_STR_UI_XNSTRING(random, random_len),
180 SILC_STR_UI_XNSTRING(id_data, id_len),
181 SILC_STR_UI_XNSTRING(pk, pk_len),
184 ret = silc_memdup(buf->data, buf->len);
189 silc_buffer_free(buf);
196 /* Generates Authentication Payload with authentication data. This is used
197 to do public key based authentication. This generates the random data
198 and the actual authentication data. Returns NULL on error. */
200 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
201 SilcPrivateKey private_key,
203 const void *id, SilcIdType type)
205 unsigned char *random;
206 unsigned char auth_data[1024];
213 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
215 /* Get 256 bytes of random data */
216 random = silc_rng_global_get_rn_data(256);
220 /* Encode the auth data */
221 tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type,
226 /* Allocate PKCS object */
227 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
228 memset(tmp, 0, tmp_len);
232 silc_pkcs_public_key_set(pkcs, public_key);
233 silc_pkcs_private_key_set(pkcs, private_key);
235 /* Compute the hash and the signature. */
236 if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
238 memset(random, 0, 256);
239 memset(tmp, 0, tmp_len);
242 silc_pkcs_free(pkcs);
246 /* Encode Authentication Payload */
247 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, random, 256,
248 auth_data, auth_len);
250 memset(tmp, 0, tmp_len);
251 memset(auth_data, 0, sizeof(auth_data));
252 memset(random, 0, 256);
255 silc_pkcs_free(pkcs);
260 /* Verifies the authentication data. Returns TRUE if authentication was
263 bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
264 SilcPublicKey public_key, SilcHash hash,
265 const void *id, SilcIdType type)
271 SILC_LOG_DEBUG(("Verifying authentication data"));
273 /* Encode auth data */
274 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
278 SILC_LOG_DEBUG(("Authentication failed"));
282 /* Allocate PKCS object */
283 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
284 memset(tmp, 0, tmp_len);
288 silc_pkcs_public_key_set(pkcs, public_key);
290 /* Verify the authentication data */
291 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
292 payload->auth_len, tmp, tmp_len)) {
294 memset(tmp, 0, tmp_len);
296 silc_pkcs_free(pkcs);
297 SILC_LOG_DEBUG(("Authentication failed"));
301 memset(tmp, 0, tmp_len);
303 silc_pkcs_free(pkcs);
305 SILC_LOG_DEBUG(("Authentication successful"));
310 /* Same as above but the payload is not parsed yet. This will parse it. */
312 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
314 SilcPublicKey public_key,
316 const void *id, SilcIdType type)
318 SilcAuthPayload auth_payload;
321 auth_payload = silc_auth_payload_parse(payload, payload_len);
323 SILC_LOG_DEBUG(("Authentication failed"));
327 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
330 silc_auth_payload_free(auth_payload);
335 /* Verifies the authentication data directly from the Authentication
336 Payload. Supports all authentication methods. If the authentication
337 method is passphrase based then the `auth_data' and `auth_data_len'
338 are the passphrase and its length. If the method is public key
339 authentication then the `auth_data' is the SilcPublicKey and the
340 `auth_data_len' is ignored. */
342 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
343 const void *auth_data, uint32 auth_data_len,
344 SilcHash hash, const void *id, SilcIdType type)
346 SILC_LOG_DEBUG(("Verifying authentication"));
348 if (auth_method != payload->auth_method)
351 switch (payload->auth_method) {
353 /* No authentication */
354 SILC_LOG_DEBUG(("No authentication required"));
357 case SILC_AUTH_PASSWORD:
358 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
359 arguments are not needed. */
360 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
361 SILC_LOG_DEBUG(("Authentication successful"));
366 case SILC_AUTH_PUBLIC_KEY:
367 /* Public key based authentication */
368 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
376 SILC_LOG_DEBUG(("Authentication failed"));
381 /* Same as above but parses the authentication payload before verify. */
383 bool silc_auth_verify_data(const unsigned char *payload, uint32 payload_len,
384 SilcAuthMethod auth_method, const void *auth_data,
385 uint32 auth_data_len, SilcHash hash,
386 const void *id, SilcIdType type)
388 SilcAuthPayload auth_payload;
391 auth_payload = silc_auth_payload_parse(payload, payload_len);
395 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
398 silc_auth_payload_free(auth_payload);
403 /******************************************************************************
405 Key Agreement Payload
407 ******************************************************************************/
409 /* The Key Agreement protocol structure */
410 struct SilcKeyAgreementPayloadStruct {
412 unsigned char *hostname;
416 /* Parses and returns an allocated Key Agreement payload. */
418 SilcKeyAgreementPayload
419 silc_key_agreement_payload_parse(const unsigned char *payload,
422 SilcBufferStruct buffer;
423 SilcKeyAgreementPayload new;
426 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
428 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
429 new = silc_calloc(1, sizeof(*new));
431 /* Parse the payload */
432 ret = silc_buffer_unformat(&buffer,
433 SILC_STR_UI16_NSTRING_ALLOC(&new->hostname,
435 SILC_STR_UI_INT(&new->port),
445 /* Encodes the Key Agreement protocol and returns the encoded buffer */
447 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
451 uint32 len = hostname ? strlen(hostname) : 0;
453 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
455 buffer = silc_buffer_alloc(2 + len + 4);
456 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
457 silc_buffer_format(buffer,
458 SILC_STR_UI_SHORT(len),
459 SILC_STR_UI_XNSTRING(hostname, len),
460 SILC_STR_UI_INT(port),
466 /* Frees the Key Agreement protocol */
468 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
471 silc_free(payload->hostname);
476 /* Returns the hostname in the payload */
478 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
480 return payload->hostname;
483 /* Returns the port in the payload */
485 uint32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
487 return payload->port;