5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2007 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.
24 /******************************************************************************
26 Authentication Payload
28 ******************************************************************************/
30 /* Authentication Payload structure */
31 struct SilcAuthPayloadStruct {
33 unsigned char *random_data;
34 unsigned char *auth_data;
37 SilcUInt16 auth_method;
38 SilcUInt16 random_len;
41 /* Parses and returns Authentication Payload */
43 SilcAuthPayload silc_auth_payload_parse(SilcStack stack,
44 const unsigned char *data,
47 SilcBufferStruct buffer;
51 SILC_LOG_DEBUG(("Parsing Authentication Payload"));
53 silc_buffer_set(&buffer, (unsigned char *)data, data_len);
56 stack = silc_stack_alloc(0, stack);
58 newp = silc_scalloc(stack, 1, sizeof(*newp));
60 silc_stack_free(stack);
65 /* Parse the payload */
66 ret = silc_buffer_sunformat(stack, &buffer,
67 SILC_STR_UI_SHORT(&newp->len),
68 SILC_STR_UI_SHORT(&newp->auth_method),
69 SILC_STR_UI16_NSTRING_ALLOC(&newp->random_data,
71 SILC_STR_UI16_NSTRING_ALLOC(&newp->auth_data,
75 silc_sfree(stack, newp);
76 silc_stack_free(stack);
80 if (newp->len != silc_buffer_len(&buffer) ||
81 newp->random_len + newp->auth_len > silc_buffer_len(&buffer) - 8) {
82 silc_auth_payload_free(newp);
86 /* Authentication data must be provided */
87 if (newp->auth_len < 1) {
88 silc_auth_payload_free(newp);
92 /* If password authentication, random data must not be set */
93 if (newp->auth_method == SILC_AUTH_PASSWORD && newp->random_len) {
94 silc_auth_payload_free(newp);
98 /* If public key authentication, random data must be at least 128 bytes */
99 if (newp->auth_method == SILC_AUTH_PUBLIC_KEY && newp->random_len < 128) {
100 silc_auth_payload_free(newp);
107 /* Encodes authentication payload into buffer and returns it */
109 SilcBuffer silc_auth_payload_encode(SilcStack stack,
110 SilcAuthMethod method,
111 const unsigned char *random_data,
112 SilcUInt16 random_len,
113 const unsigned char *auth_data,
118 unsigned char *autf8 = NULL;
119 SilcUInt32 autf8_len;
121 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
123 /* Passphrase MUST be UTF-8 encoded, encode if it is not */
124 if (method == SILC_AUTH_PASSWORD && !silc_utf8_valid(auth_data, auth_len)) {
125 autf8_len = silc_utf8_encoded_len(auth_data, auth_len, 0);
128 autf8 = silc_scalloc(stack, autf8_len, sizeof(*autf8));
129 auth_len = silc_utf8_encode(auth_data, auth_len, 0, autf8, autf8_len);
130 auth_data = (const unsigned char *)autf8;
133 len = 2 + 2 + 2 + random_len + 2 + auth_len;
134 buffer = silc_buffer_salloc_size(stack, len);
136 silc_sfree(stack, autf8);
140 silc_buffer_sformat(stack, buffer,
141 SILC_STR_UI_SHORT(len),
142 SILC_STR_UI_SHORT(method),
143 SILC_STR_UI_SHORT(random_len),
144 SILC_STR_UI_XNSTRING(random_data, random_len),
145 SILC_STR_UI_SHORT(auth_len),
146 SILC_STR_UI_XNSTRING(auth_data, auth_len),
149 silc_sfree(stack, autf8);
153 /* Frees authentication payload. */
155 void silc_auth_payload_free(SilcAuthPayload payload)
158 SilcStack stack = payload->stack;
160 if (payload->random_data) {
161 memset(payload->random_data, 0, payload->random_len);
162 silc_sfree(stack, payload->random_data);
164 if (payload->auth_data) {
165 memset(payload->auth_data, 0, payload->auth_len);
166 silc_sfree(stack, payload->auth_data);
169 silc_sfree(stack, payload);
170 silc_stack_free(stack);
174 /* Get authentication method */
176 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
178 return payload->auth_method;
181 /* Get the public data from the auth payload. */
183 unsigned char *silc_auth_get_public_data(SilcAuthPayload payload,
184 SilcUInt32 *pubdata_len)
187 *pubdata_len = (SilcUInt32)payload->random_len;
189 return payload->random_data;
192 /* Get the authentication data. If this is passphrase it is UTF-8 encoded. */
194 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
195 SilcUInt32 *auth_len)
198 *auth_len = (SilcUInt32)payload->auth_len;
200 return payload->auth_data;
203 /******************************************************************************
205 Authentication Routines
207 ******************************************************************************/
209 /* Encodes the authentication data for hashing and signing as the protocol
212 static unsigned char *
213 silc_auth_public_key_encode_data(SilcStack stack,
214 SilcPublicKey public_key,
215 const unsigned char *randomdata,
216 SilcUInt32 random_len, const void *id,
217 SilcIdType type, SilcUInt32 *ret_len)
220 unsigned char *pk, id_data[32], *ret;
221 SilcUInt32 pk_len, id_len;
223 pk = silc_pkcs_public_key_encode(stack, public_key, &pk_len);
227 if (!silc_id_id2str(id, type, id_data, sizeof(id_data), &id_len)) {
232 buf = silc_buffer_salloc_size(stack, random_len + id_len + pk_len);
237 silc_buffer_sformat(stack, buf,
238 SILC_STR_UI_XNSTRING(randomdata, random_len),
239 SILC_STR_UI_XNSTRING(id_data, id_len),
240 SILC_STR_UI_XNSTRING(pk, pk_len),
243 ret = silc_buffer_steal(buf, ret_len);
245 silc_buffer_sfree(stack, buf);
246 silc_sfree(stack, pk);
253 unsigned char *pubdata;
254 SilcUInt32 pubdata_len;
255 SilcAuthGenerated generated;
257 } *SilcAuthGenerateContext;
259 /* Signature callback */
262 silc_auth_public_key_auth_generate_cb(SilcBool success,
263 const unsigned char *signature,
264 SilcUInt32 signature_len,
267 SilcAuthGenerateContext a = context;
268 SilcStack stack = a->stack;
272 a->generated(NULL, context);
273 silc_sfree(stack, a->pubdata);
274 silc_sfree(stack, a);
275 silc_stack_free(stack);
279 /* Encode Authentication Payload */
280 buf = silc_auth_payload_encode(stack, SILC_AUTH_PUBLIC_KEY, a->pubdata,
281 a->pubdata_len, signature, signature_len);
283 a->generated(buf, context);
285 silc_buffer_sfree(stack, buf);
286 silc_sfree(stack, a->pubdata);
287 silc_sfree(stack, a);
288 silc_stack_free(stack);
291 /* Generates Authentication Payload with authentication data. This is used
292 to do public key based authentication. This generates the random data
293 and the actual authentication data. Returns NULL on error. */
296 silc_auth_public_key_auth_generate(SilcPublicKey public_key,
297 SilcPrivateKey private_key,
298 SilcRng rng, SilcHash hash,
299 const void *id, SilcIdType type,
300 SilcAuthGenerated generated,
303 unsigned char randomdata[256];
305 /* Get random data */
307 silc_rng_get_rn_data(rng, sizeof(randomdata), randomdata,
310 silc_rng_global_get_rn_data(rng, sizeof(randomdata), randomdata,
313 return silc_auth_public_key_auth_generate_wpub(public_key, private_key,
314 randomdata, sizeof(randomdata),
315 hash, id, type, generated,
319 /* Generates Authentication Payload with authentication data. This is used
320 to do public key based authentication. This generates the random data
321 and the actual authentication data. Returns NULL on error. */
324 silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
325 SilcPrivateKey private_key,
326 const unsigned char *pubdata,
327 SilcUInt32 pubdata_len,
329 const void *id, SilcIdType type,
330 SilcAuthGenerated generated,
333 SilcAuthGenerateContext a;
334 SilcAsyncOperation op;
339 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
341 /* We use the Crypto Toolkit's stack since we're doing crypto */
342 stack = silc_stack_alloc(2048, silc_crypto_stack());
344 a = silc_scalloc(stack, 1, sizeof(*a));
346 generated(NULL, context);
351 /* Encode the auth data */
352 tmp = silc_auth_public_key_encode_data(stack, public_key, pubdata,
353 pubdata_len, id, type, &tmp_len);
355 silc_sfree(stack, a);
356 silc_stack_free(stack);
357 generated(NULL, context);
361 a->pubdata = silc_smemdup(stack, pubdata, pubdata_len);
363 memset(tmp, 0, tmp_len);
364 silc_sfree(stack, tmp);
365 silc_sfree(stack, a);
366 silc_stack_free(stack);
367 generated(NULL, context);
371 /* Compute the hash and the signature. */
372 op = silc_pkcs_sign(private_key, tmp, tmp_len, TRUE, hash,
373 silc_auth_public_key_auth_generate_cb, a);
375 memset(tmp, 0, tmp_len);
376 silc_sfree(stack, tmp);
381 /* Verifies the authentication data. */
384 silc_auth_public_key_auth_verify(SilcAuthPayload payload,
385 SilcPublicKey public_key,
389 SilcAuthResultCb result,
392 SilcAsyncOperation op;
396 SILC_LOG_DEBUG(("Verifying authentication data"));
398 /* Encode auth data */
399 tmp = silc_auth_public_key_encode_data(payload->stack,
400 public_key, payload->random_data,
404 SILC_LOG_DEBUG(("Authentication failed"));
405 result(FALSE, context);
409 /* Verify the authentication data */
410 op = silc_pkcs_verify(public_key, payload->auth_data,
411 payload->auth_len, tmp, tmp_len, hash,
414 memset(tmp, 0, tmp_len);
415 silc_sfree(payload->stack, tmp);
420 /* Same as above but the payload is not parsed yet. This will parse it. */
423 silc_auth_public_key_auth_verify_data(const unsigned char *payload,
424 SilcUInt32 payload_len,
425 SilcPublicKey public_key,
429 SilcAuthResultCb result,
432 SilcAsyncOperation op;
433 SilcAuthPayload auth_payload;
435 auth_payload = silc_auth_payload_parse(silc_crypto_stack(), payload,
438 SILC_LOG_DEBUG(("Authentication failed"));
439 result(FALSE, context);
443 op = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
444 id, type, result, context);
446 silc_auth_payload_free(auth_payload);
451 /* Verifies the authentication data directly from the Authentication
452 Payload. Supports all authentication methods. If the authentication
453 method is passphrase based then the `auth_data' and `auth_data_len'
454 are the passphrase and its length. If the method is public key
455 authentication then the `auth_data' is the SilcPublicKey and the
456 `auth_data_len' is ignored. */
459 silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
460 const void *auth_data, SilcUInt32 auth_data_len,
461 SilcHash hash, const void *id, SilcIdType type,
462 SilcAuthResultCb result, void *context)
464 SILC_LOG_DEBUG(("Verifying authentication"));
466 if (!payload || auth_method != payload->auth_method) {
467 result(FALSE, context);
471 switch (payload->auth_method) {
473 /* No authentication */
474 SILC_LOG_DEBUG(("No authentication required"));
475 result(TRUE, context);
478 case SILC_AUTH_PASSWORD:
479 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
480 arguments are not needed. */
483 if ((payload->auth_len == 0) || !auth_data ||
484 payload->auth_len != auth_data_len)
487 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
488 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
489 result(TRUE, context);
494 case SILC_AUTH_PUBLIC_KEY:
495 /* Public key based authentication */
496 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
497 hash, id, type, result, context);
504 SILC_LOG_DEBUG(("Authentication failed"));
505 result(FALSE, context);
510 /* Same as above but parses the authentication payload before verify. */
513 silc_auth_verify_data(const unsigned char *payload,
514 SilcUInt32 payload_len,
515 SilcAuthMethod auth_method,
516 const void *auth_data,
517 SilcUInt32 auth_data_len, SilcHash hash,
518 const void *id, SilcIdType type,
519 SilcAuthResultCb result, void *context)
521 SilcAsyncOperation op;
522 SilcAuthPayload auth_payload;
524 auth_payload = silc_auth_payload_parse(silc_crypto_stack(), payload,
526 if (!auth_payload || (auth_payload->auth_len == 0)) {
527 result(FALSE, context);
531 op = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
532 hash, id, type, result, context);
534 silc_auth_payload_free(auth_payload);
539 /******************************************************************************
541 Key Agreement Payload
543 ******************************************************************************/
545 /* The Key Agreement protocol structure */
546 struct SilcKeyAgreementPayloadStruct {
547 SilcUInt16 hostname_len;
548 unsigned char *hostname;
553 /* Parses and returns an allocated Key Agreement payload. */
555 SilcKeyAgreementPayload
556 silc_key_agreement_payload_parse(const unsigned char *payload,
557 SilcUInt32 payload_len)
559 SilcBufferStruct buffer;
560 SilcKeyAgreementPayload newp;
563 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
565 newp = silc_calloc(1, sizeof(*newp));
569 /* Parse the payload */
570 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
571 ret = silc_buffer_unformat(&buffer,
572 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
573 &newp->hostname_len),
574 SILC_STR_UI_SHORT(&newp->protocol),
575 SILC_STR_UI_SHORT(&newp->port),
577 if (ret == -1 || newp->hostname_len > silc_buffer_len(&buffer) - 6) {
585 /* Encodes the Key Agreement protocol and returns the encoded buffer */
587 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
592 SilcUInt32 len = hostname ? strlen(hostname) : 0;
594 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
596 buffer = silc_buffer_alloc_size(2 + len + 4);
599 silc_buffer_format(buffer,
600 SILC_STR_UI_SHORT(len),
601 SILC_STR_UI_XNSTRING(hostname, len),
602 SILC_STR_UI_SHORT(protocol),
603 SILC_STR_UI_SHORT(port),
609 /* Frees the Key Agreement protocol */
611 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
614 silc_free(payload->hostname);
619 /* Returns the hostname in the payload */
621 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
623 return payload->hostname;
626 /* Returns the protocol in the payload */
628 SilcUInt16 silc_key_agreement_get_protocol(SilcKeyAgreementPayload payload)
630 return payload->protocol;
633 /* Returns the port in the payload */
635 SilcUInt16 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
637 return payload->port;