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, rng, 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,
330 const void *id, SilcIdType type,
331 SilcAuthGenerated generated,
334 SilcAuthGenerateContext a;
335 SilcAsyncOperation op;
340 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
342 /* We use the Crypto Toolkit's stack since we're doing crypto */
343 stack = silc_stack_alloc(2048, silc_crypto_stack());
345 a = silc_scalloc(stack, 1, sizeof(*a));
347 generated(NULL, context);
352 /* Encode the auth data */
353 tmp = silc_auth_public_key_encode_data(stack, public_key, pubdata,
354 pubdata_len, id, type, &tmp_len);
356 silc_sfree(stack, a);
357 silc_stack_free(stack);
358 generated(NULL, context);
362 a->pubdata = silc_smemdup(stack, pubdata, pubdata_len);
364 memset(tmp, 0, tmp_len);
365 silc_sfree(stack, tmp);
366 silc_sfree(stack, a);
367 silc_stack_free(stack);
368 generated(NULL, context);
372 /* Compute the hash and the signature. */
373 op = silc_pkcs_sign(private_key, tmp, tmp_len, TRUE, hash, rng,
374 silc_auth_public_key_auth_generate_cb, a);
376 memset(tmp, 0, tmp_len);
377 silc_sfree(stack, tmp);
382 /* Verifies the authentication data. */
385 silc_auth_public_key_auth_verify(SilcAuthPayload payload,
386 SilcPublicKey public_key,
390 SilcAuthResultCb result,
393 SilcAsyncOperation op;
397 SILC_LOG_DEBUG(("Verifying authentication data"));
399 /* Encode auth data */
400 tmp = silc_auth_public_key_encode_data(payload->stack,
401 public_key, payload->random_data,
405 SILC_LOG_DEBUG(("Authentication failed"));
406 result(FALSE, context);
410 /* Verify the authentication data */
411 op = silc_pkcs_verify(public_key, payload->auth_data,
412 payload->auth_len, tmp, tmp_len, hash,
415 memset(tmp, 0, tmp_len);
416 silc_sfree(payload->stack, tmp);
421 /* Same as above but the payload is not parsed yet. This will parse it. */
424 silc_auth_public_key_auth_verify_data(const unsigned char *payload,
425 SilcUInt32 payload_len,
426 SilcPublicKey public_key,
430 SilcAuthResultCb result,
433 SilcAsyncOperation op;
434 SilcAuthPayload auth_payload;
436 auth_payload = silc_auth_payload_parse(silc_crypto_stack(), payload,
439 SILC_LOG_DEBUG(("Authentication failed"));
440 result(FALSE, context);
444 op = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
445 id, type, result, context);
447 silc_auth_payload_free(auth_payload);
452 /* Verifies the authentication data directly from the Authentication
453 Payload. Supports all authentication methods. If the authentication
454 method is passphrase based then the `auth_data' and `auth_data_len'
455 are the passphrase and its length. If the method is public key
456 authentication then the `auth_data' is the SilcPublicKey and the
457 `auth_data_len' is ignored. */
460 silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
461 const void *auth_data, SilcUInt32 auth_data_len,
462 SilcHash hash, const void *id, SilcIdType type,
463 SilcAuthResultCb result, void *context)
465 SILC_LOG_DEBUG(("Verifying authentication"));
467 if (!payload || auth_method != payload->auth_method) {
468 result(FALSE, context);
472 switch (payload->auth_method) {
474 /* No authentication */
475 SILC_LOG_DEBUG(("No authentication required"));
476 result(TRUE, context);
479 case SILC_AUTH_PASSWORD:
480 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
481 arguments are not needed. */
484 if ((payload->auth_len == 0) || !auth_data ||
485 payload->auth_len != auth_data_len)
488 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
489 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
490 result(TRUE, context);
495 case SILC_AUTH_PUBLIC_KEY:
496 /* Public key based authentication */
497 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
498 hash, id, type, result, context);
505 SILC_LOG_DEBUG(("Authentication failed"));
506 result(FALSE, context);
511 /* Same as above but parses the authentication payload before verify. */
514 silc_auth_verify_data(const unsigned char *payload,
515 SilcUInt32 payload_len,
516 SilcAuthMethod auth_method,
517 const void *auth_data,
518 SilcUInt32 auth_data_len, SilcHash hash,
519 const void *id, SilcIdType type,
520 SilcAuthResultCb result, void *context)
522 SilcAsyncOperation op;
523 SilcAuthPayload auth_payload;
525 auth_payload = silc_auth_payload_parse(silc_crypto_stack(), payload,
527 if (!auth_payload || (auth_payload->auth_len == 0)) {
528 result(FALSE, context);
532 op = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
533 hash, id, type, result, context);
535 silc_auth_payload_free(auth_payload);
540 /******************************************************************************
542 Key Agreement Payload
544 ******************************************************************************/
546 /* The Key Agreement protocol structure */
547 struct SilcKeyAgreementPayloadStruct {
548 SilcUInt16 hostname_len;
549 unsigned char *hostname;
554 /* Parses and returns an allocated Key Agreement payload. */
556 SilcKeyAgreementPayload
557 silc_key_agreement_payload_parse(const unsigned char *payload,
558 SilcUInt32 payload_len)
560 SilcBufferStruct buffer;
561 SilcKeyAgreementPayload newp;
564 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
566 newp = silc_calloc(1, sizeof(*newp));
570 /* Parse the payload */
571 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
572 ret = silc_buffer_unformat(&buffer,
573 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
574 &newp->hostname_len),
575 SILC_STR_UI_SHORT(&newp->protocol),
576 SILC_STR_UI_SHORT(&newp->port),
578 if (ret == -1 || newp->hostname_len > silc_buffer_len(&buffer) - 6) {
586 /* Encodes the Key Agreement protocol and returns the encoded buffer */
588 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
593 SilcUInt32 len = hostname ? strlen(hostname) : 0;
595 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
597 buffer = silc_buffer_alloc_size(2 + len + 4);
600 silc_buffer_format(buffer,
601 SILC_STR_UI_SHORT(len),
602 SILC_STR_UI_XNSTRING(hostname, len),
603 SILC_STR_UI_SHORT(protocol),
604 SILC_STR_UI_SHORT(port),
610 /* Frees the Key Agreement protocol */
612 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
615 silc_free(payload->hostname);
620 /* Returns the hostname in the payload */
622 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
624 return payload->hostname;
627 /* Returns the protocol in the payload */
629 SilcUInt16 silc_key_agreement_get_protocol(SilcKeyAgreementPayload payload)
631 return payload->protocol;
634 /* Returns the port in the payload */
636 SilcUInt16 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
638 return payload->port;