5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2002 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 {
34 SilcUInt16 auth_method;
35 SilcUInt16 random_len;
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 newp = silc_calloc(1, sizeof(*newp));
57 /* Parse the payload */
58 ret = silc_buffer_unformat(&buffer,
59 SILC_STR_UI_SHORT(&newp->len),
60 SILC_STR_UI_SHORT(&newp->auth_method),
61 SILC_STR_UI16_NSTRING_ALLOC(&newp->random_data,
63 SILC_STR_UI16_NSTRING_ALLOC(&newp->auth_data,
71 if (newp->len != buffer.len) {
72 silc_auth_payload_free(newp);
76 /* Authentication data must be provided */
77 if (newp->auth_len < 1) {
78 silc_auth_payload_free(newp);
82 /* If password authentication, random data must not be set */
83 if (newp->auth_method == SILC_AUTH_PASSWORD && newp->random_len) {
84 silc_auth_payload_free(newp);
88 /* If public key authentication, random data must be at least 128 bytes */
89 if (newp->auth_method == SILC_AUTH_PUBLIC_KEY && newp->random_len < 128) {
90 silc_auth_payload_free(newp);
97 /* Encodes authentication payload into buffer and returns it */
99 SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
100 const unsigned char *random_data,
101 SilcUInt16 random_len,
102 const unsigned char *auth_data,
107 unsigned char *autf8 = NULL;
108 SilcUInt32 autf8_len;
110 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
112 /* Passphrase MUST be UTF-8 encoded, encode if it is not */
113 if (method == SILC_AUTH_PASSWORD && !silc_utf8_valid(auth_data, auth_len)) {
114 autf8_len = silc_utf8_encoded_len(auth_data, auth_len, 0);
117 autf8 = silc_calloc(autf8_len, sizeof(*autf8));
118 auth_len = silc_utf8_encode(auth_data, auth_len, 0, autf8, autf8_len);
119 auth_data = (const unsigned char *)autf8;
122 len = 2 + 2 + 2 + random_len + 2 + auth_len;
123 buffer = silc_buffer_alloc_size(len);
129 silc_buffer_format(buffer,
130 SILC_STR_UI_SHORT(len),
131 SILC_STR_UI_SHORT(method),
132 SILC_STR_UI_SHORT(random_len),
133 SILC_STR_UI_XNSTRING(random_data, random_len),
134 SILC_STR_UI_SHORT(auth_len),
135 SILC_STR_UI_XNSTRING(auth_data, auth_len),
142 /* Frees authentication payload. */
144 void silc_auth_payload_free(SilcAuthPayload payload)
147 if (payload->random_data) {
148 memset(payload->random_data, 0, payload->random_len);
149 silc_free(payload->random_data);
151 if (payload->auth_data) {
152 memset(payload->auth_data, 0, payload->auth_len);
153 silc_free(payload->auth_data);
159 /* Get authentication method */
161 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
163 return payload->auth_method;
166 /* Get the authentication data. If this is passphrase it is UTF-8 encoded. */
168 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
169 SilcUInt32 *auth_len)
172 *auth_len = payload->auth_len;
174 return payload->auth_data;
177 /******************************************************************************
179 Authentication Routines
181 ******************************************************************************/
183 /* Encodes the authentication data for hashing and signing as the protocol
186 static unsigned char *
187 silc_auth_public_key_encode_data(SilcPublicKey public_key,
188 const unsigned char *random,
189 SilcUInt32 random_len, const void *id,
190 SilcIdType type, SilcUInt32 *ret_len)
193 unsigned char *pk, *id_data, *ret;
194 SilcUInt32 pk_len, id_len;
196 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
200 id_data = silc_id_id2str(id, type);
205 id_len = silc_id_get_len(id, type);
207 buf = silc_buffer_alloc_size(random_len + id_len + pk_len);
213 silc_buffer_format(buf,
214 SILC_STR_UI_XNSTRING(random, random_len),
215 SILC_STR_UI_XNSTRING(id_data, id_len),
216 SILC_STR_UI_XNSTRING(pk, pk_len),
219 ret = silc_memdup(buf->data, buf->len);
226 silc_buffer_free(buf);
233 /* Generates Authentication Payload with authentication data. This is used
234 to do public key based authentication. This generates the random data
235 and the actual authentication data. Returns NULL on error. */
237 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
238 SilcPrivateKey private_key,
239 SilcRng rng, SilcHash hash,
240 const void *id, SilcIdType type)
242 unsigned char *random;
243 unsigned char auth_data[1024];
250 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
252 /* Get 256 bytes of random data */
254 random = silc_rng_get_rn_data(rng, 256);
256 random = silc_rng_global_get_rn_data(256);
260 /* Encode the auth data */
261 tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type,
266 /* Allocate PKCS object */
267 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
268 memset(tmp, 0, tmp_len);
272 silc_pkcs_public_key_set(pkcs, public_key);
273 silc_pkcs_private_key_set(pkcs, private_key);
275 /* Compute the hash and the signature. */
276 if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
278 memset(random, 0, 256);
279 memset(tmp, 0, tmp_len);
282 silc_pkcs_free(pkcs);
286 /* Encode Authentication Payload */
287 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, random, 256,
288 auth_data, auth_len);
290 memset(tmp, 0, tmp_len);
291 memset(auth_data, 0, sizeof(auth_data));
292 memset(random, 0, 256);
295 silc_pkcs_free(pkcs);
300 /* Verifies the authentication data. Returns TRUE if authentication was
303 bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
304 SilcPublicKey public_key, SilcHash hash,
305 const void *id, SilcIdType type)
311 SILC_LOG_DEBUG(("Verifying authentication data"));
313 /* Encode auth data */
314 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
318 SILC_LOG_DEBUG(("Authentication failed"));
322 /* Allocate PKCS object */
323 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
324 memset(tmp, 0, tmp_len);
328 silc_pkcs_public_key_set(pkcs, public_key);
330 /* Verify the authentication data */
331 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
332 payload->auth_len, tmp, tmp_len)) {
334 memset(tmp, 0, tmp_len);
336 silc_pkcs_free(pkcs);
337 SILC_LOG_DEBUG(("Authentication failed"));
341 memset(tmp, 0, tmp_len);
343 silc_pkcs_free(pkcs);
345 SILC_LOG_DEBUG(("Authentication successful"));
350 /* Same as above but the payload is not parsed yet. This will parse it. */
352 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
353 SilcUInt32 payload_len,
354 SilcPublicKey public_key,
356 const void *id, SilcIdType type)
358 SilcAuthPayload auth_payload;
361 auth_payload = silc_auth_payload_parse(payload, payload_len);
363 SILC_LOG_DEBUG(("Authentication failed"));
367 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
370 silc_auth_payload_free(auth_payload);
375 /* Verifies the authentication data directly from the Authentication
376 Payload. Supports all authentication methods. If the authentication
377 method is passphrase based then the `auth_data' and `auth_data_len'
378 are the passphrase and its length. If the method is public key
379 authentication then the `auth_data' is the SilcPublicKey and the
380 `auth_data_len' is ignored. */
382 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
383 const void *auth_data, SilcUInt32 auth_data_len,
384 SilcHash hash, const void *id, SilcIdType type)
386 SILC_LOG_DEBUG(("Verifying authentication"));
388 if (!payload || auth_method != payload->auth_method)
391 switch (payload->auth_method) {
393 /* No authentication */
394 SILC_LOG_DEBUG(("No authentication required"));
397 case SILC_AUTH_PASSWORD:
398 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
399 arguments are not needed. */
402 if ((payload->auth_len == 0) || !auth_data ||
403 payload->auth_len != auth_data_len)
406 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
407 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
412 case SILC_AUTH_PUBLIC_KEY:
413 /* Public key based authentication */
414 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
422 SILC_LOG_DEBUG(("Authentication failed"));
427 /* Same as above but parses the authentication payload before verify. */
429 bool silc_auth_verify_data(const unsigned char *payload,
430 SilcUInt32 payload_len,
431 SilcAuthMethod auth_method, const void *auth_data,
432 SilcUInt32 auth_data_len, SilcHash hash,
433 const void *id, SilcIdType type)
435 SilcAuthPayload auth_payload;
438 auth_payload = silc_auth_payload_parse(payload, payload_len);
439 if (!auth_payload || (auth_payload->auth_len == 0))
442 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
445 silc_auth_payload_free(auth_payload);
450 /******************************************************************************
452 Key Agreement Payload
454 ******************************************************************************/
456 /* The Key Agreement protocol structure */
457 struct SilcKeyAgreementPayloadStruct {
458 SilcUInt16 hostname_len;
459 unsigned char *hostname;
463 /* Parses and returns an allocated Key Agreement payload. */
465 SilcKeyAgreementPayload
466 silc_key_agreement_payload_parse(const unsigned char *payload,
467 SilcUInt32 payload_len)
469 SilcBufferStruct buffer;
470 SilcKeyAgreementPayload newp;
473 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
475 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
476 newp = silc_calloc(1, sizeof(*newp));
480 /* Parse the payload */
481 ret = silc_buffer_unformat(&buffer,
482 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
483 &newp->hostname_len),
484 SILC_STR_UI_INT(&newp->port),
494 /* Encodes the Key Agreement protocol and returns the encoded buffer */
496 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
500 SilcUInt32 len = hostname ? strlen(hostname) : 0;
502 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
504 buffer = silc_buffer_alloc_size(2 + len + 4);
507 silc_buffer_format(buffer,
508 SILC_STR_UI_SHORT(len),
509 SILC_STR_UI_XNSTRING(hostname, len),
510 SILC_STR_UI_INT(port),
516 /* Frees the Key Agreement protocol */
518 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
521 silc_free(payload->hostname);
526 /* Returns the hostname in the payload */
528 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
530 return payload->hostname;
533 /* Returns the port in the payload */
535 SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
537 return payload->port;