1 /*
2
3 silcauth.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2001 - 2007 Pekka Riikonen
8
9 The contents of this file are subject to one of the Licenses specified
10 in the COPYING file; You may not use this file except in compliance
11 with the License.
12
13 The software distributed under the License is distributed on an "AS IS"
14 basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15 KIND, either expressed or implied. See the COPYING file for more
16 information.
17
18 */
19 /* $Id$ */
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 SilcUInt16 len;
33 SilcUInt16 auth_method;
34 SilcUInt16 random_len;
35 unsigned char *random_data;
36 SilcUInt16 auth_len;
37 unsigned char *auth_data;
38 };
39
40 /* Parses and returns Authentication Payload */
41
silc_auth_payload_parse(const unsigned char * data,SilcUInt32 data_len)42 SilcAuthPayload silc_auth_payload_parse(const unsigned char *data,
43 SilcUInt32 data_len)
44 {
45 SilcBufferStruct buffer;
46 SilcAuthPayload newp;
47 int ret;
48
49 SILC_LOG_DEBUG(("Parsing Authentication Payload"));
50
51 silc_buffer_set(&buffer, (unsigned char *)data, data_len);
52 newp = silc_calloc(1, sizeof(*newp));
53 if (!newp)
54 return NULL;
55
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,
61 &newp->random_len),
62 SILC_STR_UI16_NSTRING_ALLOC(&newp->auth_data,
63 &newp->auth_len),
64 SILC_STR_END);
65 if (ret == -1) {
66 silc_free(newp);
67 return NULL;
68 }
69
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);
73 return NULL;
74 }
75
76 /* Authentication data must be provided */
77 if (newp->auth_len < 1) {
78 silc_auth_payload_free(newp);
79 return NULL;
80 }
81
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);
85 return NULL;
86 }
87
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);
91 return NULL;
92 }
93
94 return newp;
95 }
96
97 /* Encodes authentication payload into buffer and returns it */
98
silc_auth_payload_encode(SilcAuthMethod method,const unsigned char * random_data,SilcUInt16 random_len,const unsigned char * auth_data,SilcUInt16 auth_len)99 SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
100 const unsigned char *random_data,
101 SilcUInt16 random_len,
102 const unsigned char *auth_data,
103 SilcUInt16 auth_len)
104 {
105 SilcBuffer buffer;
106 SilcUInt32 len;
107 unsigned char *autf8 = NULL;
108 SilcUInt32 autf8_len;
109
110 SILC_LOG_DEBUG(("Encoding Authentication Payload"));
111
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);
115 if (!autf8_len)
116 return NULL;
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;
120 }
121
122 len = 2 + 2 + 2 + random_len + 2 + auth_len;
123 buffer = silc_buffer_alloc_size(len);
124 if (!buffer) {
125 silc_free(autf8);
126 return NULL;
127 }
128
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),
136 SILC_STR_END);
137
138 silc_free(autf8);
139 return buffer;
140 }
141
142 /* Frees authentication payload. */
143
silc_auth_payload_free(SilcAuthPayload payload)144 void silc_auth_payload_free(SilcAuthPayload payload)
145 {
146 if (payload) {
147 if (payload->random_data) {
148 memset(payload->random_data, 0, payload->random_len);
149 silc_free(payload->random_data);
150 }
151 if (payload->auth_data) {
152 memset(payload->auth_data, 0, payload->auth_len);
153 silc_free(payload->auth_data);
154 }
155 silc_free(payload);
156 }
157 }
158
159 /* Get authentication method */
160
silc_auth_get_method(SilcAuthPayload payload)161 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
162 {
163 return payload->auth_method;
164 }
165
166 /* Get the public data from the auth payload. */
167
silc_auth_get_public_data(SilcAuthPayload payload,SilcUInt32 * pubdata_len)168 unsigned char *silc_auth_get_public_data(SilcAuthPayload payload,
169 SilcUInt32 *pubdata_len)
170 {
171 if (pubdata_len)
172 *pubdata_len = (SilcUInt32)payload->random_len;
173
174 return payload->random_data;
175 }
176
177 /* Get the authentication data. If this is passphrase it is UTF-8 encoded. */
178
silc_auth_get_data(SilcAuthPayload payload,SilcUInt32 * auth_len)179 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
180 SilcUInt32 *auth_len)
181 {
182 if (auth_len)
183 *auth_len = (SilcUInt32)payload->auth_len;
184
185 return payload->auth_data;
186 }
187
188 /******************************************************************************
189
190 Authentication Routines
191
192 ******************************************************************************/
193
194 /* Encodes the authentication data for hashing and signing as the protocol
195 dictates. */
196
197 static unsigned char *
silc_auth_public_key_encode_data(SilcPublicKey public_key,const unsigned char * randomdata,SilcUInt32 random_len,const void * id,SilcIdType type,SilcUInt32 * ret_len)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)
202 {
203 SilcBuffer buf;
204 unsigned char *pk, id_data[32], *ret;
205 SilcUInt32 pk_len, id_len;
206
207 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
208 if (!pk)
209 return NULL;
210
211 if (!silc_id_id2str(id, type, id_data, sizeof(id_data), &id_len)) {
212 silc_free(pk);
213 return NULL;
214 }
215
216 buf = silc_buffer_alloc_size(random_len + id_len + pk_len);
217 if (!buf) {
218 silc_free(pk);
219 return NULL;
220 }
221 silc_buffer_format(buf,
222 SILC_STR_UI_XNSTRING(randomdata, random_len),
223 SILC_STR_UI_XNSTRING(id_data, id_len),
224 SILC_STR_UI_XNSTRING(pk, pk_len),
225 SILC_STR_END);
226
227 ret = silc_buffer_steal(buf, ret_len);
228
229 silc_buffer_free(buf);
230 silc_free(pk);
231
232 return ret;
233 }
234
235 /* Generates Authentication Payload with authentication data. This is used
236 to do public key based authentication. This generates the random data
237 and the actual authentication data. Returns NULL on error. */
238
silc_auth_public_key_auth_generate(SilcPublicKey public_key,SilcPrivateKey private_key,SilcRng rng,SilcHash hash,const void * id,SilcIdType type)239 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
240 SilcPrivateKey private_key,
241 SilcRng rng, SilcHash hash,
242 const void *id, SilcIdType type)
243 {
244 unsigned char *randomdata;
245 SilcBuffer buf;
246
247 /* Get 256 bytes of random data */
248 if (rng)
249 randomdata = silc_rng_get_rn_data(rng, 256);
250 else
251 randomdata = silc_rng_global_get_rn_data(256);
252 if (!randomdata)
253 return NULL;
254
255 buf = silc_auth_public_key_auth_generate_wpub(public_key, private_key,
256 randomdata, 256, hash,
257 id, type);
258
259 memset(randomdata, 0, 256);
260 silc_free(randomdata);
261
262 return buf;
263 }
264
265 /* Generates Authentication Payload with authentication data. This is used
266 to do public key based authentication. This generates the random data
267 and the actual authentication data. Returns NULL on error. */
268
269 SilcBuffer
silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,SilcPrivateKey private_key,const unsigned char * pubdata,SilcUInt32 pubdata_len,SilcHash hash,const void * id,SilcIdType type)270 silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
271 SilcPrivateKey private_key,
272 const unsigned char *pubdata,
273 SilcUInt32 pubdata_len,
274 SilcHash hash,
275 const void *id, SilcIdType type)
276 {
277 unsigned char auth_data[65536 + 1];
278 SilcUInt32 auth_len;
279 unsigned char *tmp;
280 SilcUInt32 tmp_len;
281 SilcBuffer buf;
282
283 SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
284
285 /* Encode the auth data */
286 tmp = silc_auth_public_key_encode_data(public_key, pubdata, pubdata_len, id,
287 type, &tmp_len);
288 if (!tmp)
289 return NULL;
290
291 /* Compute the hash and the signature. */
292 if (!silc_pkcs_sign(private_key, tmp, tmp_len, auth_data,
293 sizeof(auth_data) - 1, &auth_len, TRUE, hash)) {
294 memset(tmp, 0, tmp_len);
295 silc_free(tmp);
296 return NULL;
297 }
298
299 /* Encode Authentication Payload */
300 buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, pubdata, pubdata_len,
301 auth_data, auth_len);
302
303 memset(tmp, 0, tmp_len);
304 memset(auth_data, 0, sizeof(auth_data));
305 silc_free(tmp);
306
307 return buf;
308 }
309
310 /* Verifies the authentication data. Returns TRUE if authentication was
311 successful. */
312
silc_auth_public_key_auth_verify(SilcAuthPayload payload,SilcPublicKey public_key,SilcHash hash,const void * id,SilcIdType type)313 SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
314 SilcPublicKey public_key,
315 SilcHash hash,
316 const void *id, SilcIdType type)
317 {
318 unsigned char *tmp;
319 SilcUInt32 tmp_len;
320
321 SILC_LOG_DEBUG(("Verifying authentication data"));
322
323 /* Encode auth data */
324 tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
325 payload->random_len,
326 id, type, &tmp_len);
327 if (!tmp) {
328 SILC_LOG_DEBUG(("Authentication failed"));
329 return FALSE;
330 }
331
332 /* Verify the authentication data */
333 if (!silc_pkcs_verify(public_key, payload->auth_data,
334 payload->auth_len, tmp, tmp_len, hash)) {
335
336 memset(tmp, 0, tmp_len);
337 silc_free(tmp);
338 SILC_LOG_DEBUG(("Authentication failed"));
339 return FALSE;
340 }
341
342 memset(tmp, 0, tmp_len);
343 silc_free(tmp);
344
345 SILC_LOG_DEBUG(("Authentication successful"));
346
347 return TRUE;
348 }
349
350 /* Same as above but the payload is not parsed yet. This will parse it. */
351
silc_auth_public_key_auth_verify_data(const unsigned char * payload,SilcUInt32 payload_len,SilcPublicKey public_key,SilcHash hash,const void * id,SilcIdType type)352 SilcBool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
353 SilcUInt32 payload_len,
354 SilcPublicKey public_key,
355 SilcHash hash,
356 const void *id, SilcIdType type)
357 {
358 SilcAuthPayload auth_payload;
359 int ret;
360
361 auth_payload = silc_auth_payload_parse(payload, payload_len);
362 if (!auth_payload) {
363 SILC_LOG_DEBUG(("Authentication failed"));
364 return FALSE;
365 }
366
367 ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
368 id, type);
369
370 silc_auth_payload_free(auth_payload);
371
372 return ret;
373 }
374
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. */
381
silc_auth_verify(SilcAuthPayload payload,SilcAuthMethod auth_method,const void * auth_data,SilcUInt32 auth_data_len,SilcHash hash,const void * id,SilcIdType type)382 SilcBool 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)
385 {
386 SILC_LOG_DEBUG(("Verifying authentication"));
387
388 if (!payload || auth_method != payload->auth_method)
389 return FALSE;
390
391 switch (payload->auth_method) {
392 case SILC_AUTH_NONE:
393 /* No authentication */
394 SILC_LOG_DEBUG(("No authentication required"));
395 return TRUE;
396
397 case SILC_AUTH_PASSWORD:
398 /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
399 arguments are not needed. */
400
401 /* Sanity checks */
402 if ((payload->auth_len == 0) || !auth_data ||
403 payload->auth_len != auth_data_len)
404 break;
405
406 if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
407 SILC_LOG_DEBUG(("Passphrase Authentication successful"));
408 return TRUE;
409 }
410 break;
411
412 case SILC_AUTH_PUBLIC_KEY:
413 /* Public key based authentication */
414 return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
415 hash, id, type);
416 break;
417
418 default:
419 break;
420 }
421
422 SILC_LOG_DEBUG(("Authentication failed"));
423
424 return FALSE;
425 }
426
427 /* Same as above but parses the authentication payload before verify. */
428
silc_auth_verify_data(const unsigned char * payload,SilcUInt32 payload_len,SilcAuthMethod auth_method,const void * auth_data,SilcUInt32 auth_data_len,SilcHash hash,const void * id,SilcIdType type)429 SilcBool silc_auth_verify_data(const unsigned char *payload,
430 SilcUInt32 payload_len,
431 SilcAuthMethod auth_method,
432 const void *auth_data,
433 SilcUInt32 auth_data_len, SilcHash hash,
434 const void *id, SilcIdType type)
435 {
436 SilcAuthPayload auth_payload;
437 SilcBool ret;
438
439 auth_payload = silc_auth_payload_parse(payload, payload_len);
440 if (!auth_payload || (auth_payload->auth_len == 0))
441 return FALSE;
442
443 ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
444 hash, id, type);
445
446 silc_auth_payload_free(auth_payload);
447
448 return ret;
449 }
450
451 /******************************************************************************
452
453 Key Agreement Payload
454
455 ******************************************************************************/
456
457 /* The Key Agreement protocol structure */
458 struct SilcKeyAgreementPayloadStruct {
459 SilcUInt16 hostname_len;
460 unsigned char *hostname;
461 SilcUInt16 protocol;
462 SilcUInt16 port;
463 };
464
465 /* Parses and returns an allocated Key Agreement payload. */
466
467 SilcKeyAgreementPayload
silc_key_agreement_payload_parse(const unsigned char * payload,SilcUInt32 payload_len)468 silc_key_agreement_payload_parse(const unsigned char *payload,
469 SilcUInt32 payload_len)
470 {
471 SilcBufferStruct buffer;
472 SilcKeyAgreementPayload newp;
473 int ret;
474
475 SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
476
477 newp = silc_calloc(1, sizeof(*newp));
478 if (!newp)
479 return NULL;
480
481 /* Parse the payload */
482 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
483 ret = silc_buffer_unformat(&buffer,
484 SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
485 &newp->hostname_len),
486 SILC_STR_UI_SHORT(&newp->protocol),
487 SILC_STR_UI_SHORT(&newp->port),
488 SILC_STR_END);
489 if (ret == -1 || newp->hostname_len > silc_buffer_len(&buffer) - 6) {
490 silc_free(newp);
491 return NULL;
492 }
493
494 return newp;
495 }
496
497 /* Encodes the Key Agreement protocol and returns the encoded buffer */
498
silc_key_agreement_payload_encode(const char * hostname,SilcUInt16 protocol,SilcUInt16 port)499 SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
500 SilcUInt16 protocol,
501 SilcUInt16 port)
502 {
503 SilcBuffer buffer;
504 SilcUInt32 len = hostname ? strlen(hostname) : 0;
505
506 SILC_LOG_DEBUG(("Encoding Key Agreement Payload"));
507
508 buffer = silc_buffer_alloc_size(2 + len + 4);
509 if (!buffer)
510 return NULL;
511 silc_buffer_format(buffer,
512 SILC_STR_UI_SHORT(len),
513 SILC_STR_UI_XNSTRING(hostname, len),
514 SILC_STR_UI_SHORT(protocol),
515 SILC_STR_UI_SHORT(port),
516 SILC_STR_END);
517
518 return buffer;
519 }
520
521 /* Frees the Key Agreement protocol */
522
silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)523 void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload)
524 {
525 if (payload) {
526 silc_free(payload->hostname);
527 silc_free(payload);
528 }
529 }
530
531 /* Returns the hostname in the payload */
532
silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)533 char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload)
534 {
535 return payload->hostname;
536 }
537
538 /* Returns the protocol in the payload */
539
silc_key_agreement_get_protocol(SilcKeyAgreementPayload payload)540 SilcUInt16 silc_key_agreement_get_protocol(SilcKeyAgreementPayload payload)
541 {
542 return payload->protocol;
543 }
544
545 /* Returns the port in the payload */
546
silc_key_agreement_get_port(SilcKeyAgreementPayload payload)547 SilcUInt16 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
548 {
549 return payload->port;
550 }
551