5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2005 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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
24 /******************************************************************************
26 Authentication Payload
28 ******************************************************************************/
30 /* Authentication Payload structure */
31 struct SilcAuthPayloadStruct {
33 SilcUInt16 auth_method;
34 SilcUInt16 random_len;
35 unsigned char *random_data;
37 unsigned char *auth_data;
40 /* Parses and returns Authentication Payload */
42 SilcAuthPayload silc_auth_payload_parse(const unsigned char *data,
45 SilcBufferStruct buffer;
49 SILC_LOG_DEBUG(("Parsing Authentication Payload"));
51 silc_buffer_set(&buffer, (unsigned char *)data, data_len);
52 newp = silc_calloc(1, sizeof(*newp));
56 /* Parse the payload */
57 ret = silc_buffer_unformat(&buffer,
58 SILC_STR_UI_SHORT(&newp->len),
59 SILC_STR_UI_SHORT(&newp->auth_method),
60 SILC_STR_UI16_NSTRING_ALLOC(&newp->random_data,
62 SILC_STR_UI16_NSTRING_ALLOC(&newp->auth_data,
70 if (newp->len != silc_buffer_len(&buffer) ||
71 newp->random_len + newp->auth_len > silc_buffer_len(&buffer) - 8) {
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 public data from the auth payload. */
168 unsigned char *silc_auth_get_public_data(SilcAuthPayload payload,
169 SilcUInt32 *pubdata_len)
172 *pubdata_len = (SilcUInt32)payload->random_len;
174 return payload->random_data;
177 /* Get the authentication data. If this is passphrase it is UTF-8 encoded. */
179 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
180 SilcUInt32 *auth_len)
183 *auth_len = (SilcUInt32)payload->auth_len;
185 return payload->auth_data;
188 /******************************************************************************
190 Authentication Routines
192 ******************************************************************************/
194 /* Encodes the authentication data for hashing and signing as the protocol
197 static unsigned char *
198 silc_auth_public_key_encode_data(SilcPublicKey public_key,
199 const unsigned char *randomdata,
200 SilcUInt32 random_len, const void *id,
201 SilcIdType type, SilcUInt32 *ret_len)
204 unsigned char *pk, *id_data, *ret;
205 SilcUInt32 pk_len, id_len;
207 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
211 id_data = silc_id_id2str(id, type);
216 id_len = silc_id_get_len(id, type);
218 buf = silc_buffer_alloc_size(random_len + id_len + pk_len);
224 silc_buffer_format(buf,
225 SILC_STR_UI_XNSTRING(randomdata, random_len),
226 SILC_STR_UI_XNSTRING(id_data, id_len),
227 SILC_STR_UI_XNSTRING(pk, pk_len),
230 ret = silc_buffer_steal(buf, ret_len);
232 silc_buffer_free(buf);
239 /* Generates Authentication Payload with authentication data. This is used
240 to do public key based authentication. This generates the random data
241 and the actual authentication data. Returns NULL on error. */
243 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
244 SilcPrivateKey private_key,
245 SilcRng rng, SilcHash hash,
246 const void *id, SilcIdType type)
248 unsigned char *randomdata;
251 /* Get 256 bytes of random data */
253 randomdata = silc_rng_get_rn_data(rng, 256);
255 randomdata = silc_rng_global_get_rn_data(256);
259 buf = silc_auth_public_key_auth_generate_wpub(public_key, private_key,
260 randomdata, 256, hash,
263 memset(randomdata, 0, 256);
264 silc_free(randomdata);
269 /* Generates Authentication Payload with authentication data. This is used
270 to do public key based authentication. This generates the random data
271 and the actual authentication data. Returns NULL on error. */
274 silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
275 SilcPrivateKey private_key,
276 const unsigned char *pubdata,
277 SilcUInt32 pubdata_len,
279 const void *id, SilcIdType type)
281 unsigned char auth_data[2048 + 1];
288 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
290 /* Encode the auth data */
291 tmp = silc_auth_public_key_encode_data(public_key, pubdata, pubdata_len, id,
296 /* Allocate PKCS object */
297 if (!silc_pkcs_alloc(private_key->name, &pkcs)) {
298 memset(tmp, 0, tmp_len);
302 silc_pkcs_public_key_set(pkcs, public_key);
303 silc_pkcs_private_key_set(pkcs, private_key);
305 /* Compute the hash and the signature. */
306 if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
307 !silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
309 memset(tmp, 0, tmp_len);
311 silc_pkcs_free(pkcs);
315 /* Encode Authentication Payload */
316 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, pubdata, pubdata_len,
317 auth_data, auth_len);
319 memset(tmp, 0, tmp_len);
320 memset(auth_data, 0, sizeof(auth_data));
322 silc_pkcs_free(pkcs);
327 /* Verifies the authentication data. Returns TRUE if authentication was
330 bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
331 SilcPublicKey public_key, SilcHash hash,
332 const void *id, SilcIdType type)
338 SILC_LOG_DEBUG(("Verifying authentication data"));
340 /* Encode auth data */
341 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
345 SILC_LOG_DEBUG(("Authentication failed"));
349 /* Allocate PKCS object */
350 if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
351 memset(tmp, 0, tmp_len);
355 silc_pkcs_public_key_set(pkcs, public_key);
357 /* Verify the authentication data */
358 if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
359 payload->auth_len, tmp, tmp_len)) {
361 memset(tmp, 0, tmp_len);
363 silc_pkcs_free(pkcs);
364 SILC_LOG_DEBUG(("Authentication failed"));
368 memset(tmp, 0, tmp_len);
370 silc_pkcs_free(pkcs);
372 SILC_LOG_DEBUG(("Authentication successful"));
377 /* Same as above but the payload is not parsed yet. This will parse it. */
379 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
380 SilcUInt32 payload_len,
381 SilcPublicKey public_key,
383 const void *id, SilcIdType type)
385 SilcAuthPayload auth_payload;
388 auth_payload = silc_auth_payload_parse(payload, payload_len);
390 SILC_LOG_DEBUG(("Authentication failed"));
394 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
397 silc_auth_payload_free(auth_payload);
402 /* Verifies the authentication data directly from the Authentication
403 Payload. Supports all authentication methods. If the authentication
404 method is passphrase based then the `auth_data' and `auth_data_len'
405 are the passphrase and its length. If the method is public key
406 authentication then the `auth_data' is the SilcPublicKey and the
407 `auth_data_len' is ignored. */
409 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
410 const void *auth_data, SilcUInt32 auth_data_len,
411 SilcHash hash, const void *id, SilcIdType type)
413 SILC_LOG_DEBUG(("Verifying authentication"));
415 if (!payload || auth_method != payload->auth_method)
418 switch (payload->auth_method) {
420 /* No authentication */
421 SILC_LOG_DEBUG(("No authentication required"));
424 case SILC_AUTH_PASSWORD:
425 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
426 arguments are not needed. */
429 if ((payload->auth_len == 0) || !auth_data ||
430 payload->auth_len != auth_data_len)
433 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
434 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
439 case SILC_AUTH_PUBLIC_KEY:
440 /* Public key based authentication */
441 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
449 SILC_LOG_DEBUG(("Authentication failed"));
454 /* Same as above but parses the authentication payload before verify. */
456 bool silc_auth_verify_data(const unsigned char *payload,
457 SilcUInt32 payload_len,
458 SilcAuthMethod auth_method, const void *auth_data,
459 SilcUInt32 auth_data_len, SilcHash hash,
460 const void *id, SilcIdType type)
462 SilcAuthPayload auth_payload;
465 auth_payload = silc_auth_payload_parse(payload, payload_len);
466 if (!auth_payload || (auth_payload->auth_len == 0))
469 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
472 silc_auth_payload_free(auth_payload);
477 /******************************************************************************
479 Key Agreement Payload
481 ******************************************************************************/
483 /* The Key Agreement protocol structure */
484 struct SilcKeyAgreementPayloadStruct {
485 SilcUInt16 hostname_len;
486 unsigned char *hostname;
490 /* Parses and returns an allocated Key Agreement payload. */
492 SilcKeyAgreementPayload
493 silc_key_agreement_payload_parse(const unsigned char *payload,
494 SilcUInt32 payload_len)
496 SilcBufferStruct buffer;
497 SilcKeyAgreementPayload newp;
500 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
502 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
503 newp = silc_calloc(1, sizeof(*newp));
507 /* Parse the payload */
508 ret = silc_buffer_unformat(&buffer,
509 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
510 &newp->hostname_len),
511 SILC_STR_UI_INT(&newp->port),
513 if (ret == -1 || newp->hostname_len > silc_buffer_len(&buffer) - 6) {
521 /* Encodes the Key Agreement protocol and returns the encoded buffer */
523 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
527 SilcUInt32 len = hostname ? strlen(hostname) : 0;
529 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
531 buffer = silc_buffer_alloc_size(2 + len + 4);
534 silc_buffer_format(buffer,
535 SILC_STR_UI_SHORT(len),
536 SILC_STR_UI_XNSTRING(hostname, len),
537 SILC_STR_UI_INT(port),
543 /* Frees the Key Agreement protocol */
545 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
548 silc_free(payload->hostname);
553 /* Returns the hostname in the payload */
555 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
557 return payload->hostname;
560 /* Returns the port in the payload */
562 SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
564 return payload->port;