1 /*
2
3 silcauth.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2001 - 2007 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* $Id: silcauth.c,v 1.42 2007/07/21 17:18:20 priikone Exp $ */
20
21 #include "silc.h"
22 #include "silcauth.h"
23
24 /******************************************************************************
25
26 Authentication Payload
27
28 ******************************************************************************/
29
30 /* Authentication Payload structure */
31 struct SilcAuthPayloadStruct {
32 SilcStack stack;
33 unsigned char *random_data;
34 unsigned char *auth_data;
35 SilcUInt16 auth_len;
36 SilcUInt16 len;
37 SilcUInt16 auth_method;
38 SilcUInt16 random_len;
39 };
40
41 /* Parses and returns Authentication Payload */
42
43 SilcAuthPayload silc_auth_payload_parse(SilcStack stack,
44 const unsigned char *data,
45 SilcUInt32 data_len)
46 {
47 SilcBufferStruct buffer;
48 SilcAuthPayload newp;
49 int ret;
50
51 SILC_LOG_DEBUG(("Parsing Authentication Payload"));
52
53 silc_buffer_set(&buffer, (unsigned char *)data, data_len);
54
55 if (stack)
56 stack = silc_stack_alloc(0, stack);
57
58 newp = silc_scalloc(stack, 1, sizeof(*newp));
59 if (!newp) {
60 silc_stack_free(stack);
61 return NULL;
62 }
63 newp->stack = stack;
64
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,
70 &newp->random_len),
71 SILC_STR_UI16_NSTRING_ALLOC(&newp->auth_data,
72 &newp->auth_len),
73 SILC_STR_END);
74 if (ret == -1) {
75 silc_sfree(stack, newp);
76 silc_stack_free(stack);
77 return NULL;
78 }
79
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);
83 return NULL;
84 }
85
86 /* Authentication data must be provided */
87 if (newp->auth_len < 1) {
88 silc_auth_payload_free(newp);
89 return NULL;
90 }
91
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);
95 return NULL;
96 }
97
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);
101 return NULL;
102 }
103
104 return newp;
105 }
106
107 /* Encodes authentication payload into buffer and returns it */
108
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,
114 SilcUInt16 auth_len)
115 {
116 SilcBuffer buffer;
117 SilcUInt32 len;
118 unsigned char *autf8 = NULL;
119 SilcUInt32 autf8_len;
120
121 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
122
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);
126 if (!autf8_len)
127 return NULL;
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;
131 }
132
133 len = 2 + 2 + 2 + random_len + 2 + auth_len;
134 buffer = silc_buffer_salloc_size(stack, len);
135 if (!buffer) {
136 silc_sfree(stack, autf8);
137 return NULL;
138 }
139
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),
147 SILC_STR_END);
148
149 silc_sfree(stack, autf8);
150 return buffer;
151 }
152
153 /* Frees authentication payload. */
154
155 void silc_auth_payload_free(SilcAuthPayload payload)
156 {
157 if (payload) {
158 SilcStack stack = payload->stack;
159
160 if (payload->random_data) {
161 memset(payload->random_data, 0, payload->random_len);
162 silc_sfree(stack, payload->random_data);
163 }
164 if (payload->auth_data) {
165 memset(payload->auth_data, 0, payload->auth_len);
166 silc_sfree(stack, payload->auth_data);
167 }
168
169 silc_sfree(stack, payload);
170 silc_stack_free(stack);
171 }
172 }
173
174 /* Get authentication method */
175
176 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
177 {
178 return payload->auth_method;
179 }
180
181 /* Get the public data from the auth payload. */
182
183 unsigned char *silc_auth_get_public_data(SilcAuthPayload payload,
184 SilcUInt32 *pubdata_len)
185 {
186 if (pubdata_len)
187 *pubdata_len = (SilcUInt32)payload->random_len;
188
189 return payload->random_data;
190 }
191
192 /* Get the authentication data. If this is passphrase it is UTF-8 encoded. */
193
194 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
195 SilcUInt32 *auth_len)
196 {
197 if (auth_len)
198 *auth_len = (SilcUInt32)payload->auth_len;
199
200 return payload->auth_data;
201 }
202
203 /******************************************************************************
204
205 Authentication Routines
206
207 ******************************************************************************/
208
209 /* Encodes the authentication data for hashing and signing as the protocol
210 dictates. */
211
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)
218 {
219 SilcBuffer buf;
220 unsigned char *pk, id_data[32], *ret;
221 SilcUInt32 pk_len, id_len;
222
223 pk = silc_pkcs_public_key_encode(stack, public_key, &pk_len);
224 if (!pk)
225 return NULL;
226
227 if (!silc_id_id2str(id, type, id_data, sizeof(id_data), &id_len)) {
228 silc_free(pk);
229 return NULL;
230 }
231
232 buf = silc_buffer_salloc_size(stack, random_len + id_len + pk_len);
233 if (!buf) {
234 silc_free(pk);
235 return NULL;
236 }
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),
241 SILC_STR_END);
242
243 ret = silc_buffer_steal(buf, ret_len);
244
245 silc_buffer_sfree(stack, buf);
246 silc_sfree(stack, pk);
247
248 return ret;
249 }
250
251 typedef struct {
252 SilcStack stack;
253 unsigned char *pubdata;
254 SilcUInt32 pubdata_len;
255 SilcAuthGenerated generated;
256 void *context;
257 } *SilcAuthGenerateContext;
258
259 /* Signature callback */
260
261 static void
262 silc_auth_public_key_auth_generate_cb(SilcBool success,
263 const unsigned char *signature,
264 SilcUInt32 signature_len,
265 void *context)
266 {
267 SilcAuthGenerateContext a = context;
268 SilcStack stack = a->stack;
269 SilcBuffer buf;
270
271 if (!success) {
272 a->generated(NULL, context);
273 silc_sfree(stack, a->pubdata);
274 silc_sfree(stack, a);
275 silc_stack_free(stack);
276 return;
277 }
278
279 /* Encode Authentication Payload */
280 buf = silc_auth_payload_encode(stack, SILC_AUTH_PUBLIC_KEY, a->pubdata,
281 a->pubdata_len, signature, signature_len);
282
283 a->generated(buf, context);
284
285 silc_buffer_sfree(stack, buf);
286 silc_sfree(stack, a->pubdata);
287 silc_sfree(stack, a);
288 silc_stack_free(stack);
289 }
290
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. */
294
295 SilcAsyncOperation
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,
301 void *context)
302 {
303 unsigned char randomdata[256];
304
305 /* Get random data */
306 if (rng)
307 silc_rng_get_rn_data(rng, sizeof(randomdata), randomdata,
308 sizeof(randomdata));
309 else
310 silc_rng_global_get_rn_data(rng, sizeof(randomdata), randomdata,
311 sizeof(randomdata));
312
313 return silc_auth_public_key_auth_generate_wpub(public_key, private_key,
314 randomdata, sizeof(randomdata),
315 hash, rng, id, type, generated,
316 context);
317 }
318
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. */
322
323 SilcAsyncOperation
324 silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
325 SilcPrivateKey private_key,
326 const unsigned char *pubdata,
327 SilcUInt32 pubdata_len,
328 SilcHash hash,
329 SilcRng rng,
330 const void *id, SilcIdType type,
331 SilcAuthGenerated generated,
332 void *context)
333 {
334 SilcAuthGenerateContext a;
335 SilcAsyncOperation op;
336 unsigned char *tmp;
337 SilcUInt32 tmp_len;
338 SilcStack stack;
339
340 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
341
342 /* We use the Crypto Toolkit's stack since we're doing crypto */
343 stack = silc_stack_alloc(2048, silc_crypto_stack());
344
345 a = silc_scalloc(stack, 1, sizeof(*a));
346 if (!a) {
347 generated(NULL, context);
348 return NULL;
349 }
350 a->stack = stack;
351
352 /* Encode the auth data */
353 tmp = silc_auth_public_key_encode_data(stack, public_key, pubdata,
354 pubdata_len, id, type, &tmp_len);
355 if (!tmp) {
356 silc_sfree(stack, a);
357 silc_stack_free(stack);
358 generated(NULL, context);
359 return NULL;
360 }
361
362 a->pubdata = silc_smemdup(stack, pubdata, pubdata_len);
363 if (!a->pubdata) {
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);
369 return NULL;
370 }
371
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);
375
376 memset(tmp, 0, tmp_len);
377 silc_sfree(stack, tmp);
378
379 return op;
380 }
381
382 /* Verifies the authentication data. */
383
384 SilcAsyncOperation
385 silc_auth_public_key_auth_verify(SilcAuthPayload payload,
386 SilcPublicKey public_key,
387 SilcHash hash,
388 const void *id,
389 SilcIdType type,
390 SilcAuthResultCb result,
391 void *context)
392 {
393 SilcAsyncOperation op;
394 unsigned char *tmp;
395 SilcUInt32 tmp_len;
396
397 SILC_LOG_DEBUG(("Verifying authentication data"));
398
399 /* Encode auth data */
400 tmp = silc_auth_public_key_encode_data(payload->stack,
401 public_key, payload->random_data,
402 payload->random_len,
403 id, type, &tmp_len);
404 if (!tmp) {
405 SILC_LOG_DEBUG(("Authentication failed"));
406 result(FALSE, context);
407 return NULL;
408 }
409
410 /* Verify the authentication data */
411 op = silc_pkcs_verify(public_key, payload->auth_data,
412 payload->auth_len, tmp, tmp_len, hash,
413 result, context);
414
415 memset(tmp, 0, tmp_len);
416 silc_sfree(payload->stack, tmp);
417
418 return op;
419 }
420
421 /* Same as above but the payload is not parsed yet. This will parse it. */
422
423 SilcAsyncOperation
424 silc_auth_public_key_auth_verify_data(const unsigned char *payload,
425 SilcUInt32 payload_len,
426 SilcPublicKey public_key,
427 SilcHash hash,
428 const void *id,
429 SilcIdType type,
430 SilcAuthResultCb result,
431 void *context)
432 {
433 SilcAsyncOperation op;
434 SilcAuthPayload auth_payload;
435
436 auth_payload = silc_auth_payload_parse(silc_crypto_stack(), payload,
437 payload_len);
438 if (!auth_payload) {
439 SILC_LOG_DEBUG(("Authentication failed"));
440 result(FALSE, context);
441 return NULL;
442 }
443
444 op = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
445 id, type, result, context);
446
447 silc_auth_payload_free(auth_payload);
448
449 return op;
450 }
451
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. */
458
459 SilcAsyncOperation
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)
464 {
465 SILC_LOG_DEBUG(("Verifying authentication"));
466
467 if (!payload || auth_method != payload->auth_method) {
468 result(FALSE, context);
469 return NULL;
470 }
471
472 switch (payload->auth_method) {
473 case SILC_AUTH_NONE:
474 /* No authentication */
475 SILC_LOG_DEBUG(("No authentication required"));
476 result(TRUE, context);
477 return NULL;
478
479 case SILC_AUTH_PASSWORD:
480 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
481 arguments are not needed. */
482
483 /* Sanity checks */
484 if ((payload->auth_len == 0) || !auth_data ||
485 payload->auth_len != auth_data_len)
486 break;
487
488 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
489 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
490 result(TRUE, context);
491 return NULL;
492 }
493 break;
494
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);
499 break;
500
501 default:
502 break;
503 }
504
505 SILC_LOG_DEBUG(("Authentication failed"));
506 result(FALSE, context);
507
508 return NULL;
509 }
510
511 /* Same as above but parses the authentication payload before verify. */
512
513 SilcAsyncOperation
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)
521 {
522 SilcAsyncOperation op;
523 SilcAuthPayload auth_payload;
524
525 auth_payload = silc_auth_payload_parse(silc_crypto_stack(), payload,
526 payload_len);
527 if (!auth_payload || (auth_payload->auth_len == 0)) {
528 result(FALSE, context);
529 return NULL;
530 }
531
532 op = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
533 hash, id, type, result, context);
534
535 silc_auth_payload_free(auth_payload);
536
537 return op;
538 }
539
540 /******************************************************************************
541
542 Key Agreement Payload
543
544 ******************************************************************************/
545
546 /* The Key Agreement protocol structure */
547 struct SilcKeyAgreementPayloadStruct {
548 SilcUInt16 hostname_len;
549 unsigned char *hostname;
550 SilcUInt16 protocol;
551 SilcUInt16 port;
552 };
553
554 /* Parses and returns an allocated Key Agreement payload. */
555
556 SilcKeyAgreementPayload
557 silc_key_agreement_payload_parse(const unsigned char *payload,
558 SilcUInt32 payload_len)
559 {
560 SilcBufferStruct buffer;
561 SilcKeyAgreementPayload newp;
562 int ret;
563
564 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
565
566 newp = silc_calloc(1, sizeof(*newp));
567 if (!newp)
568 return NULL;
569
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),
577 SILC_STR_END);
578 if (ret == -1 || newp->hostname_len > silc_buffer_len(&buffer) - 6) {
579 silc_free(newp);
580 return NULL;
581 }
582
583 return newp;
584 }
585
586 /* Encodes the Key Agreement protocol and returns the encoded buffer */
587
588 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
589 SilcUInt16 protocol,
590 SilcUInt16 port)
591 {
592 SilcBuffer buffer;
593 SilcUInt32 len = hostname ? strlen(hostname) : 0;
594
595 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
596
597 buffer = silc_buffer_alloc_size(2 + len + 4);
598 if (!buffer)
599 return NULL;
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),
605 SILC_STR_END);
606
607 return buffer;
608 }
609
610 /* Frees the Key Agreement protocol */
611
612 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
613 {
614 if (payload) {
615 silc_free(payload->hostname);
616 silc_free(payload);
617 }
618 }
619
620 /* Returns the hostname in the payload */
621
622 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
623 {
624 return payload->hostname;
625 }
626
627 /* Returns the protocol in the payload */
628
629 SilcUInt16 silc_key_agreement_get_protocol(SilcKeyAgreementPayload payload)
630 {
631 return payload->protocol;
632 }
633
634 /* Returns the port in the payload */
635
636 SilcUInt16 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
637 {
638 return payload->port;
639 }
640
This page was automatically generated by the LXR engine.
Free-text search provided by Glimpse