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