1 /*
2 
3   silcpk.c
4 
5   Author: Pekka Riikonen <priikone@silcnet.org>
6 
7   Copyright (C) 1997 - 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 
20 #include "silc.h"
21 #include "silcpk_i.h"
22 
23 /****************************** Key generation *******************************/
24 
25 /* Generate new SILC key pair. */
26 
silc_pkcs_silc_generate_key(const char * algorithm,SilcUInt32 bits_key_len,const char * identifier,SilcRng rng,SilcPublicKey * ret_public_key,SilcPrivateKey * ret_private_key)27 SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
28 				     SilcUInt32 bits_key_len,
29 				     const char *identifier,
30 				     SilcRng rng,
31 				     SilcPublicKey *ret_public_key,
32 				     SilcPrivateKey *ret_private_key)
33 {
34   SilcSILCPublicKey pubkey;
35   SilcSILCPrivateKey privkey;
36   const SilcPKCSAlgorithm *alg;
37   const SilcPKCSObject *pkcs;
38   SilcUInt32 version;
39 
40   SILC_LOG_DEBUG(("Generating SILC %s key pair with key length %d bits",
41 		  algorithm, bits_key_len));
42 
43   if (!rng)
44     return FALSE;
45 
46   pkcs = silc_pkcs_find_pkcs(SILC_PKCS_SILC);
47   if (!pkcs)
48     return FALSE;
49 
50   /* Allocate SILC public key */
51   pubkey = silc_calloc(1, sizeof(*pubkey));
52   if (!pubkey)
53     return FALSE;
54 
55   /* Decode identifier */
56   if (!silc_pkcs_silc_decode_identifier(identifier, &pubkey->identifier))
57     return FALSE;
58 
59   if (pubkey->identifier.version && atoi(pubkey->identifier.version) >= 2)
60     version = 2;
61   else
62     version = 1;
63 
64   /* Allocate algorithm */
65   alg = silc_pkcs_find_algorithm(algorithm, (version == 1 ? "pkcs1-no-oid" :
66 					     "pkcs1"));
67   if (!alg) {
68     silc_free(pubkey);
69     return FALSE;
70   }
71   pubkey->pkcs = alg;
72 
73   /* Allocate SILC private key */
74   privkey = silc_calloc(1, sizeof(*privkey));
75   if (!privkey) {
76     silc_free(pubkey);
77     return FALSE;
78   }
79   privkey->pkcs = alg;
80 
81   /* Allocate public key */
82   *ret_public_key = silc_calloc(1, sizeof(**ret_public_key));
83   if (!(*ret_public_key)) {
84     silc_free(pubkey);
85     silc_free(privkey);
86     return FALSE;
87   }
88   (*ret_public_key)->pkcs = pkcs;
89   (*ret_public_key)->public_key = pubkey;
90 
91   /* Allocate private key */
92   *ret_private_key = silc_calloc(1, sizeof(**ret_private_key));
93   if (!(*ret_private_key)) {
94     silc_free(pubkey);
95     silc_free(privkey);
96     silc_free(*ret_public_key);
97     return FALSE;
98   }
99   (*ret_private_key)->pkcs = pkcs;
100   (*ret_private_key)->private_key = privkey;
101 
102   /* Generate the algorithm key pair */
103   if (!alg->generate_key(bits_key_len, rng, &pubkey->public_key,
104 			 &privkey->private_key)) {
105     silc_free(pubkey);
106     silc_free(privkey);
107     silc_free(*ret_public_key);
108     silc_free(*ret_private_key);
109     return FALSE;
110   }
111 
112   return TRUE;
113 }
114 
115 
116 /**************************** Utility functions ******************************/
117 
118 /* Decodes the provided `identifier' */
119 
silc_pkcs_silc_decode_identifier(const char * identifier,SilcPublicKeyIdentifier ident)120 SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
121 					  SilcPublicKeyIdentifier ident)
122 {
123   char *cp, *item;
124   int len;
125 
126   /* Protocol says that at least UN and HN must be provided as identifier */
127   if (!strstr(identifier, "UN=") || !strstr(identifier, "HN=")) {
128     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
129 		    "identifiers"));
130     return FALSE;
131   }
132 
133   cp = (char *)identifier;
134   while (cp) {
135     len = strcspn(cp, ",");
136     if (len < 1) {
137       cp = NULL;
138       break;
139     }
140     if (len - 1 >= 0 && cp[len - 1] == '\\') {
141       while (cp) {
142 	if (len + 1 > strlen(cp)) {
143 	  cp = NULL;
144 	  break;
145 	}
146 	cp += len + 1;
147 	len = strcspn(cp, ",") + len;
148 	if (len < 1) {
149 	  cp = NULL;
150 	  break;
151 	}
152 	if (len - 1 >= 0 && cp[len - 1] != '\\')
153 	  break;
154       }
155     }
156 
157     if (!cp)
158       break;
159 
160     item = silc_calloc(len + 1, sizeof(char));
161     if (!item)
162       return FALSE;
163     if (len > strlen(cp))
164       break;
165     memcpy(item, cp, len);
166 
167     if (strstr(item, "UN="))
168       ident->username = strdup(item + strcspn(cp, "=") + 1);
169     else if (strstr(item, "HN="))
170       ident->host = strdup(item + strcspn(cp, "=") + 1);
171     else if (strstr(item, "RN="))
172       ident->realname = strdup(item + strcspn(cp, "=") + 1);
173     else if (strstr(item, "E="))
174       ident->email = strdup(item + strcspn(cp, "=") + 1);
175     else if (strstr(item, "O="))
176       ident->org = strdup(item + strcspn(cp, "=") + 1);
177     else if (strstr(item, "C="))
178       ident->country = strdup(item + strcspn(cp, "=") + 1);
179     else if (strstr(item, "V="))
180       ident->version = strdup(item + strcspn(cp, "=") + 1);
181 
182     cp += len;
183     if (strlen(cp) < 1)
184       cp = NULL;
185     else
186       cp += 1;
187 
188     if (item)
189       silc_free(item);
190   }
191 
192   return TRUE;
193 }
194 
195 /* Encodes and returns SILC public key identifier.  If some of the
196    arguments is NULL those are not encoded into the identifier string.
197    Protocol says that at least username and host must be provided. */
198 
silc_pkcs_silc_encode_identifier(char * username,char * host,char * realname,char * email,char * org,char * country,char * version)199 char *silc_pkcs_silc_encode_identifier(char *username, char *host,
200 				       char *realname, char *email,
201 				       char *org, char *country,
202 				       char *version)
203 {
204   SilcBufferStruct buf;
205   char *identifier;
206 
207   if (!username || !host)
208     return NULL;
209   if (strlen(username) < 1 || strlen(host) < 1)
210     return NULL;
211 
212   memset(&buf, 0, sizeof(buf));
213 
214   if (username)
215     silc_buffer_format(&buf,
216 		       SILC_STR_ADVANCE,
217 		       SILC_STR_UI32_STRING("UN="),
218 		       SILC_STR_UI32_STRING(username),
219 		       SILC_STR_END);
220 
221   if (host)
222     silc_buffer_format(&buf,
223 		       SILC_STR_ADVANCE,
224 		       SILC_STR_UI32_STRING(", "),
225 		       SILC_STR_UI32_STRING("HN="),
226 		       SILC_STR_UI32_STRING(host),
227 		       SILC_STR_END);
228 
229   if (realname)
230     silc_buffer_format(&buf,
231 		       SILC_STR_ADVANCE,
232 		       SILC_STR_UI32_STRING(", "),
233 		       SILC_STR_UI32_STRING("RN="),
234 		       SILC_STR_UI32_STRING(realname),
235 		       SILC_STR_END);
236 
237   if (email)
238     silc_buffer_format(&buf,
239 		       SILC_STR_ADVANCE,
240 		       SILC_STR_UI32_STRING(", "),
241 		       SILC_STR_UI32_STRING("E="),
242 		       SILC_STR_UI32_STRING(email),
243 		       SILC_STR_END);
244 
245   if (org)
246     silc_buffer_format(&buf,
247 		       SILC_STR_ADVANCE,
248 		       SILC_STR_UI32_STRING(", "),
249 		       SILC_STR_UI32_STRING("O="),
250 		       SILC_STR_UI32_STRING(org),
251 		       SILC_STR_END);
252 
253   if (country)
254     silc_buffer_format(&buf,
255 		       SILC_STR_ADVANCE,
256 		       SILC_STR_UI32_STRING(", "),
257 		       SILC_STR_UI32_STRING("C="),
258 		       SILC_STR_UI32_STRING(country),
259 		       SILC_STR_END);
260 
261   if (version) {
262     if (strlen(version) > 1 || !isdigit(version[0])) {
263       silc_buffer_purge(&buf);
264       return NULL;
265     }
266     silc_buffer_format(&buf,
267 		       SILC_STR_ADVANCE,
268 		       SILC_STR_UI32_STRING(", "),
269 		       SILC_STR_UI32_STRING("V="),
270 		       SILC_STR_UI32_STRING(version),
271 		       SILC_STR_END);
272   }
273 
274   silc_buffer_format(&buf, SILC_STR_UI_CHAR(0), SILC_STR_END);
275 
276   identifier = silc_buffer_steal(&buf, NULL);
277   return identifier;
278 }
279 
280 /* Return SILC public key version */
281 
silc_pkcs_silc_public_key_version(SilcPublicKey public_key)282 int silc_pkcs_silc_public_key_version(SilcPublicKey public_key)
283 {
284   SilcSILCPublicKey silc_pubkey;
285 
286   if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC)
287     return -1;
288 
289   silc_pubkey = public_key->public_key;
290 
291   /* If version identifire is not present it is version 1. */
292   if (!silc_pubkey->identifier.version)
293     return 1;
294 
295   return atoi(silc_pubkey->identifier.version);
296 }
297 
298 /*************************** Public key routines *****************************/
299 
300 /* Returns PKCS algorithm context */
301 
silc_pkcs_silc_get_algorithm(void * public_key)302 const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key)
303 {
304   SilcSILCPublicKey silc_pubkey = public_key;
305   return silc_pubkey->pkcs;
306 }
307 
308 /* Imports SILC protocol style public key from SILC public key file */
309 
silc_pkcs_silc_import_public_key_file(unsigned char * filedata,SilcUInt32 filedata_len,SilcPKCSFileEncoding encoding,void ** ret_public_key)310 SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
311 					       SilcUInt32 filedata_len,
312 					       SilcPKCSFileEncoding encoding,
313 					       void **ret_public_key)
314 {
315   SilcUInt32 i, len;
316   unsigned char *data = NULL;
317   int ret;
318 
319   SILC_LOG_DEBUG(("Parsing SILC public key file"));
320 
321   if (!ret_public_key)
322     return FALSE;
323 
324   /* Check start of file and remove header from the data. */
325   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
326   if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END)) {
327     SILC_LOG_ERROR(("Malformed SILC public key header"));
328     return FALSE;
329   }
330   for (i = 0; i < len; i++) {
331     if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
332       SILC_LOG_ERROR(("Malformed SILC public key header"));
333       return FALSE;
334     }
335     filedata++;
336   }
337   filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
338 		   strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
339 
340   switch (encoding) {
341   case SILC_PKCS_FILE_BIN:
342     break;
343 
344   case SILC_PKCS_FILE_BASE64:
345     data = silc_base64_decode(filedata, filedata_len, &filedata_len);
346     if (!data)
347       return FALSE;
348     filedata = data;
349     break;
350   }
351 
352   ret = silc_pkcs_silc_import_public_key(filedata, filedata_len,
353 					 ret_public_key);
354   silc_free(data);
355 
356   return ret ? TRUE : FALSE;
357 }
358 
359 /* Imports SILC protocol style public key */
360 
silc_pkcs_silc_import_public_key(unsigned char * key,SilcUInt32 key_len,void ** ret_public_key)361 int silc_pkcs_silc_import_public_key(unsigned char *key,
362 				     SilcUInt32 key_len,
363 				     void **ret_public_key)
364 {
365   const SilcPKCSAlgorithm *pkcs;
366   SilcBufferStruct buf, alg_key;
367   SilcSILCPublicKey silc_pubkey = NULL;
368   SilcAsn1 asn1 = NULL;
369   SilcUInt32 totlen, keydata_len;
370   SilcUInt16 pkcs_len, identifier_len;
371   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
372   int ret;
373 
374   SILC_LOG_DEBUG(("Parsing SILC public key"));
375 
376   if (!ret_public_key)
377     return 0;
378 
379   silc_buffer_set(&buf, key, key_len);
380 
381   /* Get length */
382   ret = silc_buffer_unformat(&buf,
383 			     SILC_STR_ADVANCE,
384 			     SILC_STR_UI_INT(&totlen),
385 			     SILC_STR_END);
386   if (ret == -1)
387     goto err;
388 
389   /* Backwards compatibility */
390   if (totlen == key_len)
391     totlen -= 4;
392 
393   if (totlen + 4 != key_len)
394     goto err;
395 
396   /* Get algorithm name and identifier */
397   ret =
398     silc_buffer_unformat(&buf,
399 			 SILC_STR_ADVANCE,
400 			 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
401 			 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
402 			 SILC_STR_END);
403   if (ret == -1)
404     goto err;
405 
406   if (pkcs_len < 1 || identifier_len < 3 ||
407       pkcs_len + identifier_len > totlen)
408     goto err;
409 
410   /* Get key data */
411   keydata_len = silc_buffer_len(&buf);
412   ret = silc_buffer_unformat(&buf,
413 			     SILC_STR_DATA(&key_data, keydata_len),
414 			     SILC_STR_END);
415   if (ret == -1)
416     goto err;
417 
418   /* Allocate SILC public key context */
419   silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
420   if (!silc_pubkey)
421     goto err;
422 
423   /* Decode SILC identifier */
424   if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
425     goto err;
426 
427   asn1 = silc_asn1_alloc();
428   if (!asn1)
429     goto err;
430 
431   SILC_LOG_DEBUG(("Public key version %s",
432 		  (!silc_pubkey->identifier.version ? "1" :
433 		   silc_pubkey->identifier.version)));
434 
435   if (!strcmp(pkcs_name, "rsa")) {
436     /* Parse the SILC RSA public key */
437     SilcUInt32 e_len, n_len;
438     SilcMPInt n, e;
439 
440     /* Get PKCS object.  Different PKCS #1 scheme is used with different
441        versions. */
442     if (!silc_pubkey->identifier.version ||
443 	atoi(silc_pubkey->identifier.version) <= 1) {
444       /* Version 1 */
445       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
446     } else {
447       /* Version 2 and newer */
448       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
449     }
450     if (!pkcs) {
451       SILC_LOG_DEBUG(("Unsupported PKCS algorithm: rsa"));
452       goto err;
453     }
454     silc_pubkey->pkcs = pkcs;
455 
456     if (keydata_len < 4)
457       goto err;
458     SILC_GET32_MSB(e_len, key_data);
459     if (!e_len || e_len + 4 > keydata_len)
460       goto err;
461     silc_mp_init(&e);
462     silc_mp_bin2mp(key_data + 4, e_len, &e);
463     if (keydata_len < 4 + e_len + 4) {
464       silc_mp_uninit(&e);
465       goto err;
466     }
467     SILC_GET32_MSB(n_len, key_data + 4 + e_len);
468     if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
469       silc_mp_uninit(&e);
470       goto err;
471     }
472     silc_mp_init(&n);
473     silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
474 
475     /* Encode to PKCS #1 format */
476     memset(&alg_key, 0, sizeof(alg_key));
477     if (!silc_asn1_encode(asn1, &alg_key,
478 			  SILC_ASN1_SEQUENCE,
479 			    SILC_ASN1_INT(&n),
480 			    SILC_ASN1_INT(&e),
481 			  SILC_ASN1_END, SILC_ASN1_END)) {
482       silc_mp_uninit(&e);
483       silc_mp_uninit(&n);
484       goto err;
485     }
486 
487     silc_mp_uninit(&e);
488     silc_mp_uninit(&n);
489 
490   } else if (!strcmp(pkcs_name, "dsa")) {
491     SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
492     goto err;
493 
494   } else {
495     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
496     goto err;
497   }
498 
499   /* Import PKCS algorithm public key */
500   if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
501 			       &silc_pubkey->public_key))
502     goto err;
503 
504   silc_free(pkcs_name);
505   silc_free(ident);
506   silc_asn1_free(asn1);
507 
508   *ret_public_key = silc_pubkey;
509 
510   return key_len;
511 
512  err:
513   silc_free(pkcs_name);
514   silc_free(ident);
515   silc_free(silc_pubkey);
516   if (asn1)
517     silc_asn1_free(asn1);
518   return 0;
519 }
520 
521 /* Exports public key as SILC protocol style public key file */
522 
523 unsigned char *
silc_pkcs_silc_export_public_key_file(void * public_key,SilcPKCSFileEncoding encoding,SilcUInt32 * ret_len)524 silc_pkcs_silc_export_public_key_file(void *public_key,
525 				      SilcPKCSFileEncoding encoding,
526 				      SilcUInt32 *ret_len)
527 {
528   SilcBuffer buf;
529   unsigned char *key, *data;
530   SilcUInt32 key_len;
531 
532   SILC_LOG_DEBUG(("Encoding SILC public key file"));
533 
534   /* Export key */
535   key = silc_pkcs_silc_export_public_key(public_key, &key_len);
536   if (!key)
537     return NULL;
538 
539   switch (encoding) {
540   case SILC_PKCS_FILE_BIN:
541     break;
542 
543   case SILC_PKCS_FILE_BASE64:
544     data = silc_base64_encode_file(key, key_len);
545     if (!data)
546       return NULL;
547     silc_free(key);
548     key = data;
549     key_len = strlen(data);
550     break;
551   }
552 
553   /* Encode SILC public key file */
554   buf = silc_buffer_alloc_size(key_len +
555 			       (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
556 				strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
557   if (!buf) {
558     silc_free(key);
559     return NULL;
560   }
561 
562   if (silc_buffer_format(buf,
563 			 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
564 			 SILC_STR_UI_XNSTRING(key, key_len),
565 			 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
566 			 SILC_STR_END) < 0) {
567     silc_buffer_free(buf);
568     silc_free(key);
569     return NULL;
570   }
571 
572   silc_free(key);
573   key = silc_buffer_steal(buf, ret_len);
574   silc_buffer_free(buf);
575 
576   return key;
577 }
578 
579 /* Exports public key as SILC protocol style public key */
580 
silc_pkcs_silc_export_public_key(void * public_key,SilcUInt32 * ret_len)581 unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
582 						SilcUInt32 *ret_len)
583 {
584   SilcSILCPublicKey silc_pubkey = public_key;
585   const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
586   SilcBufferStruct alg_key;
587   SilcBuffer buf = NULL;
588   SilcAsn1 asn1 = NULL;
589   unsigned char *pk = NULL, *key = NULL, *ret;
590   SilcUInt32 pk_len, key_len, totlen;
591   char *identifier;
592 
593   SILC_LOG_DEBUG(("Encoding SILC public key"));
594 
595   /* Export PKCS algorithm public key */
596   if (pkcs->export_public_key)
597     pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
598   if (!pk) {
599     SILC_LOG_ERROR(("Error exporting PKCS algorithm key"));
600     return NULL;
601   }
602   silc_buffer_set(&alg_key, pk, pk_len);
603 
604   /* Encode identifier */
605   identifier =
606     silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
607 				     silc_pubkey->identifier.host,
608 				     silc_pubkey->identifier.realname,
609 				     silc_pubkey->identifier.email,
610 				     silc_pubkey->identifier.org,
611 				     silc_pubkey->identifier.country,
612 				     silc_pubkey->identifier.version);
613   if (!identifier) {
614     SILC_LOG_ERROR(("Error encoding SILC public key identifier"));
615     goto err;
616   }
617 
618   asn1 = silc_asn1_alloc();
619   if (!asn1)
620     goto err;
621 
622   if (!strcmp(pkcs->name, "rsa")) {
623     /* Parse the PKCS #1 public key */
624     SilcMPInt n, e;
625     SilcUInt32 n_len, e_len;
626     unsigned char *nb, *eb;
627 
628     memset(&n, 0, sizeof(n));
629     memset(&e, 0, sizeof(e));
630     if (!silc_asn1_decode(asn1, &alg_key,
631 			  SILC_ASN1_SEQUENCE,
632 			    SILC_ASN1_INT(&n),
633 			    SILC_ASN1_INT(&e),
634 			  SILC_ASN1_END, SILC_ASN1_END))
635       goto err;
636 
637     /* Encode to SILC RSA public key */
638     eb = silc_mp_mp2bin(&e, 0, &e_len);
639     if (!eb)
640       goto err;
641     nb = silc_mp_mp2bin(&n, 0, &n_len);
642     if (!nb)
643       goto err;
644     key_len = e_len + 4 + n_len + 4;
645     key = silc_calloc(key_len, sizeof(*key));
646     if (!key)
647       goto err;
648 
649     /* Put e length and e */
650     SILC_PUT32_MSB(e_len, key);
651     memcpy(key + 4, eb, e_len);
652 
653     /* Put n length and n. */
654     SILC_PUT32_MSB(n_len, key + 4 + e_len);
655     memcpy(key + 4 + e_len + 4, nb, n_len);
656 
657     silc_free(nb);
658     silc_free(eb);
659 
660   } else if (!strcmp(pkcs->name, "dsa")) {
661     SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
662     goto err;
663 
664   } else {
665     SILC_LOG_ERROR(("Unsupported PKCS algorithm: %s", pkcs->name));
666     goto err;
667   }
668 
669   /* Encode SILC Public Key */
670   totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
671   buf = silc_buffer_alloc_size(totlen + 4);
672   if (!buf)
673     goto err;
674   if (silc_buffer_format(buf,
675 			 SILC_STR_UI_INT(totlen),
676 			 SILC_STR_UI_SHORT(strlen(pkcs->name)),
677 			 SILC_STR_UI32_STRING(pkcs->name),
678 			 SILC_STR_UI_SHORT(strlen(identifier)),
679 			 SILC_STR_UI32_STRING(identifier),
680 			 SILC_STR_UI_XNSTRING(key, key_len),
681 			 SILC_STR_END) < 0)
682     goto err;
683 
684   ret = silc_buffer_steal(buf, ret_len);
685   silc_buffer_free(buf);
686   silc_free(key);
687   silc_free(identifier);
688   silc_buffer_purge(&alg_key);
689   silc_asn1_free(asn1);
690 
691   return ret;
692 
693  err:
694   silc_free(identifier);
695   silc_free(pk);
696   silc_free(key);
697   if (buf)
698     silc_buffer_free(buf);
699   if (asn1)
700     silc_asn1_free(asn1);
701   return NULL;
702 }
703 
704 /* Return key length */
705 
silc_pkcs_silc_public_key_bitlen(void * public_key)706 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
707 {
708   SilcSILCPublicKey silc_pubkey = public_key;
709   return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
710 }
711 
712 /* Copy public key */
713 
silc_pkcs_silc_public_key_copy(void * public_key)714 void *silc_pkcs_silc_public_key_copy(void *public_key)
715 {
716   SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
717   SilcPublicKeyIdentifier ident = &silc_pubkey->identifier;
718 
719   new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
720   if (!new_pubkey)
721     return NULL;
722   new_pubkey->pkcs = silc_pubkey->pkcs;
723 
724   new_pubkey->public_key =
725     silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
726   if (!new_pubkey->public_key) {
727     silc_free(new_pubkey);
728     return NULL;
729   }
730 
731   if (ident->username)
732     new_pubkey->identifier.username =
733       silc_memdup(ident->username, strlen(ident->username));
734   if (ident->host)
735     new_pubkey->identifier.host =
736       silc_memdup(ident->host, strlen(ident->host));
737   if (ident->realname)
738     new_pubkey->identifier.realname =
739       silc_memdup(ident->realname, strlen(ident->realname));
740   if (ident->email)
741     new_pubkey->identifier.email =
742       silc_memdup(ident->email, strlen(ident->email));
743   if (ident->org)
744     new_pubkey->identifier.org =
745       silc_memdup(ident->org, strlen(ident->org));
746   if (ident->country)
747     new_pubkey->identifier.country =
748       silc_memdup(ident->country, strlen(ident->country));
749   if (ident->version)
750     new_pubkey->identifier.version =
751       silc_memdup(ident->version, strlen(ident->version));
752 
753   return new_pubkey;
754 }
755 
756 /* Compares public keys */
757 
silc_pkcs_silc_public_key_compare(void * key1,void * key2)758 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
759 {
760   SilcSILCPublicKey k1 = key1, k2 = key2;
761 
762   if (strcmp(k1->pkcs->name, k2->pkcs->name))
763     return FALSE;
764 
765   if ((k1->identifier.username && !k2->identifier.username) ||
766       (!k1->identifier.username && k2->identifier.username) ||
767       (k1->identifier.username && k2->identifier.username &&
768        strcmp(k1->identifier.username, k2->identifier.username)))
769     return FALSE;
770 
771   if ((k1->identifier.host && !k2->identifier.host) ||
772       (!k1->identifier.host && k2->identifier.host) ||
773       (k1->identifier.host && k2->identifier.host &&
774        strcmp(k1->identifier.host, k2->identifier.host)))
775     return FALSE;
776 
777   if ((k1->identifier.realname && !k2->identifier.realname) ||
778       (!k1->identifier.realname && k2->identifier.realname) ||
779       (k1->identifier.realname && k2->identifier.realname &&
780        strcmp(k1->identifier.realname, k2->identifier.realname)))
781     return FALSE;
782 
783   if ((k1->identifier.email && !k2->identifier.email) ||
784       (!k1->identifier.email && k2->identifier.email) ||
785       (k1->identifier.email && k2->identifier.email &&
786        strcmp(k1->identifier.email, k2->identifier.email)))
787     return FALSE;
788 
789   if ((k1->identifier.org && !k2->identifier.org) ||
790       (!k1->identifier.org && k2->identifier.org) ||
791       (k1->identifier.org && k2->identifier.org &&
792        strcmp(k1->identifier.org, k2->identifier.org)))
793     return FALSE;
794 
795   if ((k1->identifier.country && !k2->identifier.country) ||
796       (!k1->identifier.country && k2->identifier.country) ||
797       (k1->identifier.country && k2->identifier.country &&
798        strcmp(k1->identifier.country, k2->identifier.country)))
799     return FALSE;
800 
801   if ((k1->identifier.version && !k2->identifier.version) ||
802       (!k1->identifier.version && k2->identifier.version) ||
803       (k1->identifier.version && k2->identifier.version &&
804        strcmp(k1->identifier.version, k2->identifier.version)))
805     return FALSE;
806 
807   return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
808 }
809 
810 /* Frees public key */
811 
silc_pkcs_silc_public_key_free(void * public_key)812 void silc_pkcs_silc_public_key_free(void *public_key)
813 {
814   SilcSILCPublicKey silc_pubkey = public_key;
815 
816   silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
817 
818   silc_free(silc_pubkey->identifier.username);
819   silc_free(silc_pubkey->identifier.host);
820   silc_free(silc_pubkey->identifier.realname);
821   silc_free(silc_pubkey->identifier.email);
822   silc_free(silc_pubkey->identifier.org);
823   silc_free(silc_pubkey->identifier.country);
824   silc_free(silc_pubkey->identifier.version);
825   silc_free(silc_pubkey);
826 }
827 
828 
829 /*************************** Private key routines ****************************/
830 
831 /* Private key file magic */
832 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
833 
834 /* Imports SILC implementation style private key file */
835 
silc_pkcs_silc_import_private_key_file(unsigned char * filedata,SilcUInt32 filedata_len,const char * passphrase,SilcUInt32 passphrase_len,SilcPKCSFileEncoding encoding,void ** ret_private_key)836 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
837 						SilcUInt32 filedata_len,
838 						const char *passphrase,
839 						SilcUInt32 passphrase_len,
840 						SilcPKCSFileEncoding encoding,
841 						void **ret_private_key)
842 {
843   SilcCipher aes;
844   SilcHash sha1;
845   SilcHmac sha1hmac;
846   SilcUInt32 blocklen;
847   unsigned char tmp[32], keymat[64], *data = NULL;
848   SilcUInt32 i, len, magic, mac_len;
849   int ret;
850 
851   SILC_LOG_DEBUG(("Parsing SILC private key file"));
852 
853   /* Check start of file and remove header from the data. */
854   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
855   if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END)) {
856     SILC_LOG_ERROR(("Malformed SILC private key header"));
857     return FALSE;
858   }
859   for (i = 0; i < len; i++) {
860     if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
861       SILC_LOG_ERROR(("Malformed SILC private key header"));
862       return FALSE;
863     }
864     filedata++;
865   }
866 
867   len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
868 			strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
869 
870   switch (encoding) {
871   case SILC_PKCS_FILE_BIN:
872     break;
873 
874   case SILC_PKCS_FILE_BASE64:
875     data = silc_base64_decode(filedata, filedata_len, &len);
876     if (!data)
877       return FALSE;
878     filedata = data;
879     break;
880   }
881 
882   memset(tmp, 0, sizeof(tmp));
883   memset(keymat, 0, sizeof(keymat));
884 
885   /* Check file magic */
886   SILC_GET32_MSB(magic, filedata);
887   if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
888     SILC_LOG_DEBUG(("Private key does not have correct magic"));
889     return FALSE;
890   }
891 
892   /* Allocate the AES cipher */
893   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
894     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
895     return FALSE;
896   }
897   blocklen = silc_cipher_get_block_len(aes);
898   if (blocklen * 2 > sizeof(tmp)) {
899     silc_cipher_free(aes);
900     return FALSE;
901   }
902 
903   /* Allocate SHA1 hash */
904   if (!silc_hash_alloc("sha1", &sha1)) {
905     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
906     silc_cipher_free(aes);
907     return FALSE;
908   }
909 
910   /* Allocate HMAC */
911   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
912     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
913     silc_hash_free(sha1);
914     silc_cipher_free(aes);
915     return FALSE;
916   }
917 
918   /* Derive the decryption key from the provided key material.  The key
919      is 256 bits length, and derived by taking hash of the data, then
920      re-hashing the data and the previous digest, and using the first and
921      second digest as the key. */
922   silc_hash_init(sha1);
923   silc_hash_update(sha1, passphrase, passphrase_len);
924   silc_hash_final(sha1, keymat);
925   silc_hash_init(sha1);
926   silc_hash_update(sha1, passphrase, passphrase_len);
927   silc_hash_update(sha1, keymat, 16);
928   silc_hash_final(sha1, keymat + 16);
929 
930   /* Set the key to the cipher */
931   silc_cipher_set_key(aes, keymat, 256, FALSE);
932 
933   /* First, verify the MAC of the private key data */
934   mac_len = silc_hmac_len(sha1hmac);
935   silc_hmac_init_with_key(sha1hmac, keymat, 16);
936   silc_hmac_update(sha1hmac, filedata, len - mac_len);
937   silc_hmac_final(sha1hmac, tmp, NULL);
938   if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
939     SILC_LOG_DEBUG(("Integrity check for private key failed"));
940     memset(keymat, 0, sizeof(keymat));
941     memset(tmp, 0, sizeof(tmp));
942     silc_hmac_free(sha1hmac);
943     silc_hash_free(sha1);
944     silc_cipher_free(aes);
945     return FALSE;
946   }
947   filedata += 4;
948   len -= 4;
949 
950   /* Decrypt the private key buffer */
951   silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
952   SILC_GET32_MSB(i, filedata);
953   if (i > len) {
954     SILC_LOG_DEBUG(("Bad private key length in buffer!"));
955     memset(keymat, 0, sizeof(keymat));
956     memset(tmp, 0, sizeof(tmp));
957     silc_hmac_free(sha1hmac);
958     silc_hash_free(sha1);
959     silc_cipher_free(aes);
960     return FALSE;
961   }
962   filedata += 4;
963   len = i;
964 
965   /* Cleanup */
966   memset(keymat, 0, sizeof(keymat));
967   memset(tmp, 0, sizeof(tmp));
968   silc_hmac_free(sha1hmac);
969   silc_hash_free(sha1);
970   silc_cipher_free(aes);
971 
972   /* Import the private key */
973   ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
974 
975   silc_free(data);
976 
977   return ret ? TRUE : FALSE;
978 }
979 
980 /* Private key version */
981 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
982 #define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1
983 
984 /* Imports SILC implementation style private key */
985 
silc_pkcs_silc_import_private_key(unsigned char * key,SilcUInt32 key_len,void ** ret_private_key)986 int silc_pkcs_silc_import_private_key(unsigned char *key,
987 				      SilcUInt32 key_len,
988 				      void **ret_private_key)
989 {
990   SilcBufferStruct buf;
991   const SilcPKCSAlgorithm *pkcs;
992   SilcBufferStruct alg_key;
993   SilcSILCPrivateKey silc_privkey = NULL;
994   SilcAsn1 asn1 = NULL;
995   SilcUInt16 pkcs_len;
996   SilcUInt32 keydata_len;
997   unsigned char *pkcs_name = NULL, *key_data;
998   int ret;
999 
1000   SILC_LOG_DEBUG(("Parsing SILC private key"));
1001 
1002   if (!ret_private_key)
1003     return 0;
1004 
1005   silc_buffer_set(&buf, key, key_len);
1006 
1007   /* Get algorithm name and identifier */
1008   ret =
1009     silc_buffer_unformat(&buf,
1010 			 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
1011 			 SILC_STR_END);
1012   if (ret == -1) {
1013     SILC_LOG_DEBUG(("Cannot decode private key buffer"));
1014     goto err;
1015   }
1016 
1017   if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
1018     SILC_LOG_DEBUG(("Malformed private key buffer"));
1019     goto err;
1020   }
1021 
1022   /* Get key data. We assume that rest of the buffer is key data. */
1023   silc_buffer_pull(&buf, 2 + pkcs_len);
1024   keydata_len = silc_buffer_len(&buf);
1025   ret = silc_buffer_unformat(&buf,
1026 			     SILC_STR_UI_XNSTRING(&key_data, keydata_len),
1027 			     SILC_STR_END);
1028   if (ret == -1)
1029     goto err;
1030 
1031   /* Allocate SILC private key context */
1032   silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
1033   if (!silc_privkey)
1034     goto err;
1035 
1036   asn1 = silc_asn1_alloc();
1037   if (!asn1)
1038     goto err;
1039 
1040   if (!strcmp(pkcs_name, "rsa")) {
1041     /* Parse the RSA SILC private key */
1042     SilcBufferStruct k;
1043     SilcMPInt n, e, d, dp, dq, qp, p, q;
1044     unsigned char *tmp;
1045     SilcUInt32 len, ver;
1046 
1047     if (keydata_len < 4)
1048       goto err;
1049     silc_buffer_set(&k, key_data, keydata_len);
1050 
1051     /* Get version.  Key without the version is old style private key
1052        and we need to do some computation to get it to correct format. */
1053     if (silc_buffer_unformat(&k,
1054 			     SILC_STR_UI_INT(&ver),
1055 			     SILC_STR_END) < 0)
1056       goto err;
1057     silc_buffer_pull(&k, 4);
1058 
1059     if (ver != SILC_PRIVATE_KEY_VERSION_1 &&
1060 	ver != SILC_PRIVATE_KEY_VERSION_2) {
1061       len = ver;
1062       ver = 0;
1063     } else {
1064       if (silc_buffer_unformat(&k,
1065 			       SILC_STR_UI_INT(&len),
1066 			       SILC_STR_END) < 0)
1067 	goto err;
1068       silc_buffer_pull(&k, 4);
1069     }
1070 
1071     /* Get PKCS object.  Different PKCS #1 scheme is used with different
1072        versions. */
1073     if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
1074       /* Version 0 and 1 */
1075       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
1076     } else {
1077       /* Version 2 and newer */
1078       pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
1079     }
1080     if (!pkcs) {
1081       SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1082       goto err;
1083     }
1084     silc_privkey->pkcs = pkcs;
1085 
1086     SILC_LOG_DEBUG(("Private key version %s",
1087 		    (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
1088 		     ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0")));
1089 
1090     /* Get e */
1091     if (silc_buffer_unformat(&k,
1092 			     SILC_STR_DATA(&tmp, len),
1093 			     SILC_STR_END) < 0)
1094       goto err;
1095     silc_mp_init(&e);
1096     silc_mp_bin2mp(tmp, len, &e);
1097     silc_buffer_pull(&k, len);
1098 
1099     /* Get n */
1100     if (silc_buffer_unformat(&k,
1101 			     SILC_STR_UI_INT(&len),
1102 			     SILC_STR_END) < 0)
1103       goto err;
1104     silc_buffer_pull(&k, 4);
1105     if (silc_buffer_unformat(&k,
1106 			     SILC_STR_DATA(&tmp, len),
1107 			     SILC_STR_END) < 0)
1108       goto err;
1109     silc_mp_init(&n);
1110     silc_mp_bin2mp(tmp, len, &n);
1111     silc_buffer_pull(&k, len);
1112 
1113     /* Get d */
1114     if (silc_buffer_unformat(&k,
1115 			     SILC_STR_UI_INT(&len),
1116 			     SILC_STR_END) < 0)
1117       goto err;
1118     silc_buffer_pull(&k, 4);
1119     if (silc_buffer_unformat(&k,
1120 			     SILC_STR_DATA(&tmp, len),
1121 			     SILC_STR_END) < 0)
1122       goto err;
1123     silc_mp_init(&d);
1124     silc_mp_bin2mp(tmp, len, &d);
1125     silc_buffer_pull(&k, len);
1126 
1127     /* Get dP */
1128     if (silc_buffer_unformat(&k,
1129 			     SILC_STR_UI_INT(&len),
1130 			     SILC_STR_END) < 0)
1131       goto err;
1132     silc_buffer_pull(&k, 4);
1133     if (silc_buffer_unformat(&k,
1134 			     SILC_STR_DATA(&tmp, len),
1135 			     SILC_STR_END) < 0)
1136       goto err;
1137     silc_mp_init(&dp);
1138     silc_mp_bin2mp(tmp, len, &dp);
1139     silc_buffer_pull(&k, len);
1140 
1141     /* Get dQ */
1142     if (silc_buffer_unformat(&k,
1143 			     SILC_STR_UI_INT(&len),
1144 			     SILC_STR_END) < 0)
1145       goto err;
1146     silc_buffer_pull(&k, 4);
1147     if (silc_buffer_unformat(&k,
1148 			     SILC_STR_DATA(&tmp, len),
1149 			     SILC_STR_END) < 0)
1150       goto err;
1151     silc_mp_init(&dq);
1152     silc_mp_bin2mp(tmp, len, &dq);
1153     silc_buffer_pull(&k, len);
1154 
1155     if (ver == 0) {
1156       /* Old version */
1157 
1158       /* Get pQ len */
1159       if (silc_buffer_unformat(&k,
1160 			       SILC_STR_UI_INT(&len),
1161 			       SILC_STR_END) < 0)
1162 	goto err;
1163       silc_buffer_pull(&k, 4);
1164       if (silc_buffer_len(&k) < len)
1165 	goto err;
1166       silc_buffer_pull(&k, len);
1167 
1168       /* Get qP len */
1169       if (silc_buffer_unformat(&k,
1170 			       SILC_STR_UI_INT(&len),
1171 			       SILC_STR_END) < 0)
1172 	goto err;
1173       silc_buffer_pull(&k, 4);
1174       if (silc_buffer_len(&k) < len)
1175 	goto err;
1176       silc_buffer_pull(&k, len);
1177     } else {
1178       /* New version */
1179 
1180       /* Get qP */
1181       if (silc_buffer_unformat(&k,
1182 			       SILC_STR_UI_INT(&len),
1183 			       SILC_STR_END) < 0)
1184 	goto err;
1185       silc_buffer_pull(&k, 4);
1186       if (silc_buffer_unformat(&k,
1187 			       SILC_STR_DATA(&tmp, len),
1188 			       SILC_STR_END) < 0)
1189 	goto err;
1190       silc_mp_init(&qp);
1191       silc_mp_bin2mp(tmp, len, &qp);
1192       silc_buffer_pull(&k, len);
1193     }
1194 
1195     /* Get p */
1196     if (silc_buffer_unformat(&k,
1197 			     SILC_STR_UI_INT(&len),
1198 			     SILC_STR_END) < 0)
1199       goto err;
1200     silc_buffer_pull(&k, 4);
1201     if (silc_buffer_unformat(&k,
1202 			     SILC_STR_DATA(&tmp, len),
1203 			     SILC_STR_END) < 0)
1204       goto err;
1205     silc_mp_init(&p);
1206     silc_mp_bin2mp(tmp, len, &p);
1207     silc_buffer_pull(&k, len);
1208 
1209     /* Get q */
1210     if (silc_buffer_unformat(&k,
1211 			     SILC_STR_UI_INT(&len),
1212 			     SILC_STR_END) < 0)
1213       goto err;
1214     silc_buffer_pull(&k, 4);
1215     if (silc_buffer_unformat(&k,
1216 			     SILC_STR_DATA(&tmp, len),
1217 			     SILC_STR_END) < 0)
1218       goto err;
1219     silc_mp_init(&q);
1220     silc_mp_bin2mp(tmp, len, &q);
1221     silc_buffer_pull(&k, len);
1222 
1223     if (ver == 0) {
1224       /* Old version.  Compute to new version */
1225       SILC_LOG_DEBUG(("Old version private key"));
1226       silc_mp_init(&qp);
1227       silc_mp_modinv(&qp, &q, &p);
1228     }
1229 
1230     /* Encode to PKCS #1 format */
1231     memset(&alg_key, 0, sizeof(alg_key));
1232     if (!silc_asn1_encode(asn1, &alg_key,
1233 			  SILC_ASN1_SEQUENCE,
1234 			    SILC_ASN1_SHORT_INT(0),
1235 			    SILC_ASN1_INT(&n),
1236 			    SILC_ASN1_INT(&e),
1237 			    SILC_ASN1_INT(&d),
1238 			    SILC_ASN1_INT(&p),
1239 			    SILC_ASN1_INT(&q),
1240 			    SILC_ASN1_INT(&dp),
1241 			    SILC_ASN1_INT(&dq),
1242 			    SILC_ASN1_INT(&qp),
1243 			  SILC_ASN1_END, SILC_ASN1_END))
1244       goto err;
1245 
1246     silc_mp_uninit(&n);
1247     silc_mp_uninit(&e);
1248     silc_mp_uninit(&e);
1249     silc_mp_uninit(&d);
1250     silc_mp_uninit(&p);
1251     silc_mp_uninit(&q);
1252     silc_mp_uninit(&dp);
1253     silc_mp_uninit(&dq);
1254     silc_mp_uninit(&qp);
1255 
1256   } else if (!strcmp(pkcs_name, "dsa")) {
1257     SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1258     goto err;
1259 
1260   } else {
1261     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1262     goto err;
1263   }
1264 
1265   /* Import PKCS algorithm private key */
1266   if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
1267 				&silc_privkey->private_key))
1268     goto err;
1269 
1270   silc_free(pkcs_name);
1271   silc_asn1_free(asn1);
1272 
1273   *ret_private_key = silc_privkey;
1274 
1275   return key_len;
1276 
1277  err:
1278   silc_free(pkcs_name);
1279   silc_free(silc_privkey);
1280   if (asn1)
1281     silc_asn1_free(asn1);
1282   SILC_LOG_ERROR(("Malformed SILC private key "));
1283   return 0;
1284 }
1285 
1286 /* Exports private key as SILC implementation style private key file */
1287 
1288 unsigned char *
silc_pkcs_silc_export_private_key_file(void * private_key,const char * passphrase,SilcUInt32 passphrase_len,SilcPKCSFileEncoding encoding,SilcRng rng,SilcUInt32 * ret_len)1289 silc_pkcs_silc_export_private_key_file(void *private_key,
1290 				       const char *passphrase,
1291 				       SilcUInt32 passphrase_len,
1292 				       SilcPKCSFileEncoding encoding,
1293 				       SilcRng rng,
1294 				       SilcUInt32 *ret_len)
1295 {
1296   SilcCipher aes;
1297   SilcHash sha1;
1298   SilcHmac sha1hmac;
1299   SilcBuffer buf, enc;
1300   SilcUInt32 len, blocklen, padlen, key_len;
1301   unsigned char *key, *data;
1302   unsigned char tmp[32], keymat[64];
1303   int i;
1304 
1305   SILC_LOG_DEBUG(("Encoding SILC private key file"));
1306 
1307   /* Export the private key */
1308   key = silc_pkcs_silc_export_private_key(private_key, &key_len);
1309   if (!key)
1310     return NULL;
1311 
1312   memset(tmp, 0, sizeof(tmp));
1313   memset(keymat, 0, sizeof(keymat));
1314 
1315   /* Allocate the AES cipher */
1316   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1317     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1318     silc_free(key);
1319     return NULL;
1320   }
1321   blocklen = silc_cipher_get_block_len(aes);
1322   if (blocklen * 2 > sizeof(tmp)) {
1323     silc_cipher_free(aes);
1324     silc_free(key);
1325     return NULL;
1326   }
1327 
1328   /* Allocate SHA1 hash */
1329   if (!silc_hash_alloc("sha1", &sha1)) {
1330     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1331     silc_cipher_free(aes);
1332     return NULL;
1333   }
1334 
1335   /* Allocate HMAC */
1336   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1337     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1338     silc_hash_free(sha1);
1339     silc_cipher_free(aes);
1340     return NULL;
1341   }
1342 
1343   /* Derive the encryption key from the provided key material.  The key
1344      is 256 bits length, and derived by taking hash of the data, then
1345      re-hashing the data and the previous digest, and using the first and
1346      second digest as the key. */
1347   silc_hash_init(sha1);
1348   silc_hash_update(sha1, passphrase, passphrase_len);
1349   silc_hash_final(sha1, keymat);
1350   silc_hash_init(sha1);
1351   silc_hash_update(sha1, passphrase, passphrase_len);
1352   silc_hash_update(sha1, keymat, 16);
1353   silc_hash_final(sha1, keymat + 16);
1354 
1355   /* Set the key to the cipher */
1356   silc_cipher_set_key(aes, keymat, 256, TRUE);
1357 
1358   /* Encode the buffer to be encrypted.  Add padding to it too, at least
1359      block size of the cipher. */
1360 
1361   /* Allocate buffer for encryption */
1362   len = silc_hmac_len(sha1hmac);
1363   padlen = 16 + (16 - ((key_len + 4) % blocklen));
1364   enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
1365   if (!enc) {
1366     silc_hmac_free(sha1hmac);
1367     silc_hash_free(sha1);
1368     silc_cipher_free(aes);
1369     return FALSE;
1370   }
1371 
1372   /* Generate padding */
1373   for (i = 0; i < padlen; i++)
1374     tmp[i] = silc_rng_get_byte_fast(rng);
1375 
1376   /* Put magic number */
1377   SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1378   silc_buffer_pull(enc, 4);
1379 
1380   /* Encode the buffer */
1381   silc_buffer_format(enc,
1382 		     SILC_STR_UI_INT(key_len),
1383 		     SILC_STR_UI_XNSTRING(key, key_len),
1384 		     SILC_STR_UI_XNSTRING(tmp, padlen),
1385 		     SILC_STR_END);
1386   silc_free(key);
1387 
1388   /* Encrypt. */
1389   silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1390 		      silc_cipher_get_iv(aes));
1391 
1392   silc_buffer_push(enc, 4);
1393 
1394   /* Compute HMAC over the encrypted data and append the MAC to data.
1395      The key is the first digest of the original key material. */
1396   key_len = silc_buffer_len(enc) - len;
1397   silc_hmac_init_with_key(sha1hmac, keymat, 16);
1398   silc_hmac_update(sha1hmac, enc->data, key_len);
1399   silc_buffer_pull(enc, key_len);
1400   silc_hmac_final(sha1hmac, enc->data, NULL);
1401   silc_buffer_push(enc, key_len);
1402 
1403   /* Cleanup */
1404   memset(keymat, 0, sizeof(keymat));
1405   memset(tmp, 0, sizeof(tmp));
1406   silc_hmac_free(sha1hmac);
1407   silc_hash_free(sha1);
1408   silc_cipher_free(aes);
1409 
1410   switch (encoding) {
1411   case SILC_PKCS_FILE_BIN:
1412     break;
1413 
1414   case SILC_PKCS_FILE_BASE64:
1415     data = silc_base64_encode_file(enc->data, silc_buffer_len(enc));
1416     if (!data) {
1417       silc_buffer_clear(enc);
1418       silc_buffer_free(enc);
1419       return NULL;
1420     }
1421     silc_free(silc_buffer_steal(enc, NULL));
1422     silc_buffer_set(enc, data, strlen(data));
1423     break;
1424   }
1425 
1426   key = enc->data;
1427   key_len = silc_buffer_len(enc);
1428 
1429   /* Encode the data and save to file */
1430   len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1431 		   strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1432   buf = silc_buffer_alloc_size(len);
1433   if (!buf) {
1434     silc_buffer_free(enc);
1435     return NULL;
1436   }
1437   silc_buffer_format(buf,
1438 		     SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1439 		     SILC_STR_UI_XNSTRING(key, key_len),
1440 		     SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1441 		     SILC_STR_END);
1442 
1443   silc_buffer_free(enc);
1444   data = silc_buffer_steal(buf, ret_len);
1445   silc_buffer_free(buf);
1446 
1447   return data;
1448 }
1449 
1450 /* Exports private key as SILC implementation style private key */
1451 
silc_pkcs_silc_export_private_key(void * private_key,SilcUInt32 * ret_len)1452 unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
1453 						 SilcUInt32 *ret_len)
1454 {
1455   SilcSILCPrivateKey silc_privkey = private_key;
1456   const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
1457   SilcBufferStruct alg_key;
1458   SilcBuffer buf = NULL;
1459   SilcAsn1 asn1 = NULL;
1460   unsigned char *prv = NULL, *key = NULL, *ret;
1461   SilcUInt32 prv_len, key_len, totlen;
1462 
1463   SILC_LOG_DEBUG(("Encoding SILC private key"));
1464 
1465   /* Export PKCS algorithm private key */
1466   if (pkcs->export_private_key)
1467     prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
1468   if (!prv)
1469     return NULL;
1470   silc_buffer_set(&alg_key, prv, prv_len);
1471 
1472   asn1 = silc_asn1_alloc();
1473   if (!asn1)
1474     goto err;
1475 
1476   if (!strcmp(pkcs->name, "rsa")) {
1477     /* Parse the PKCS #1 private key */
1478     SilcMPInt n, e, d, dp, dq, qp, p, q;
1479     SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1480       qp_len, p_len, q_len, len = 0;
1481     unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1482 
1483     if (!silc_asn1_decode(asn1, &alg_key,
1484 			  SILC_ASN1_SEQUENCE,
1485 			    SILC_ASN1_INT(NULL),
1486 			    SILC_ASN1_INT(&n),
1487 			    SILC_ASN1_INT(&e),
1488 			    SILC_ASN1_INT(&d),
1489 			    SILC_ASN1_INT(&p),
1490 			    SILC_ASN1_INT(&q),
1491 			    SILC_ASN1_INT(&dp),
1492 			    SILC_ASN1_INT(&dq),
1493 			    SILC_ASN1_INT(&qp),
1494 			  SILC_ASN1_END, SILC_ASN1_END))
1495       goto err;
1496 
1497     /* Encode to SILC RSA private key */
1498     eb = silc_mp_mp2bin(&e, 0, &e_len);
1499     nb = silc_mp_mp2bin(&n, 0, &n_len);
1500     db = silc_mp_mp2bin(&d, 0, &d_len);
1501     dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1502     dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1503     qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1504     pb = silc_mp_mp2bin(&p, 0, &p_len);
1505     qb = silc_mp_mp2bin(&q, 0, &q_len);
1506     len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1507       dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1508 
1509     buf = silc_buffer_alloc_size(len);
1510     if (!buf)
1511       goto err;
1512     if (silc_buffer_format(buf,
1513 			   SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1514 			   SILC_STR_UI_INT(e_len),
1515 			   SILC_STR_UI_XNSTRING(eb, e_len),
1516 			   SILC_STR_UI_INT(n_len),
1517 			   SILC_STR_UI_XNSTRING(nb, n_len),
1518 			   SILC_STR_UI_INT(d_len),
1519 			   SILC_STR_UI_XNSTRING(db, d_len),
1520 			   SILC_STR_UI_INT(dp_len),
1521 			   SILC_STR_UI_XNSTRING(dpb, dp_len),
1522 			   SILC_STR_UI_INT(dq_len),
1523 			   SILC_STR_UI_XNSTRING(dqb, dq_len),
1524 			   SILC_STR_UI_INT(qp_len),
1525 			   SILC_STR_UI_XNSTRING(qpb, qp_len),
1526 			   SILC_STR_UI_INT(p_len),
1527 			   SILC_STR_UI_XNSTRING(pb, p_len),
1528 			   SILC_STR_UI_INT(q_len),
1529 			   SILC_STR_UI_XNSTRING(qb, q_len),
1530 			   SILC_STR_END) < 0)
1531       goto err;
1532 
1533     key = silc_buffer_steal(buf, &key_len);
1534     silc_buffer_free(buf);
1535     silc_free(nb);
1536     silc_free(eb);
1537     silc_free(db);
1538     silc_free(dpb);
1539     silc_free(dqb);
1540     silc_free(qpb);
1541     silc_free(pb);
1542     silc_free(qb);
1543 
1544   } else if (!strcmp(pkcs->name, "dsa")) {
1545     SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1546     goto err;
1547 
1548   } else {
1549     SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1550     goto err;
1551   }
1552 
1553   /* Encode SILC private key */
1554   totlen = 2 + strlen(pkcs->name) + key_len;
1555   buf = silc_buffer_alloc_size(totlen);
1556   if (!buf)
1557     goto err;
1558   if (silc_buffer_format(buf,
1559 			 SILC_STR_UI_SHORT(strlen(pkcs->name)),
1560 			 SILC_STR_UI32_STRING(pkcs->name),
1561 			 SILC_STR_UI_XNSTRING(key, key_len),
1562 			 SILC_STR_END) < 0)
1563     goto err;
1564 
1565   ret = silc_buffer_steal(buf, ret_len);
1566   silc_buffer_free(buf);
1567   silc_free(prv);
1568   silc_free(key);
1569   silc_asn1_free(asn1);
1570 
1571   return ret;
1572 
1573  err:
1574   silc_free(prv);
1575   silc_free(key);
1576   if (buf)
1577     silc_buffer_free(buf);
1578   return NULL;
1579 }
1580 
1581 /* Return key length */
1582 
silc_pkcs_silc_private_key_bitlen(void * private_key)1583 SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
1584 {
1585   SilcSILCPrivateKey silc_privkey = private_key;
1586   return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
1587 }
1588 
1589 /* Frees private key */
1590 
silc_pkcs_silc_private_key_free(void * private_key)1591 void silc_pkcs_silc_private_key_free(void *private_key)
1592 {
1593   SilcSILCPrivateKey silc_privkey = private_key;
1594 
1595   silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
1596 
1597   silc_free(silc_privkey);
1598 }
1599 
1600 
1601 /***************************** PKCS operations ******************************/
1602 
1603 /* Encrypts as specified in SILC protocol specification */
1604 
silc_pkcs_silc_encrypt(void * public_key,unsigned char * src,SilcUInt32 src_len,unsigned char * dst,SilcUInt32 dst_size,SilcUInt32 * ret_dst_len,SilcRng rng)1605 SilcBool silc_pkcs_silc_encrypt(void *public_key,
1606 				unsigned char *src,
1607 				SilcUInt32 src_len,
1608 				unsigned char *dst,
1609 				SilcUInt32 dst_size,
1610 				SilcUInt32 *ret_dst_len,
1611 				SilcRng rng)
1612 {
1613   SilcSILCPublicKey silc_pubkey = public_key;
1614 
1615   if (!silc_pubkey->pkcs->encrypt)
1616     return FALSE;
1617 
1618   return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
1619 				    src, src_len,
1620 				    dst, dst_size, ret_dst_len, rng);
1621 }
1622 
1623 /* Decrypts as specified in SILC protocol specification */
1624 
silc_pkcs_silc_decrypt(void * private_key,unsigned char * src,SilcUInt32 src_len,unsigned char * dst,SilcUInt32 dst_size,SilcUInt32 * ret_dst_len)1625 SilcBool silc_pkcs_silc_decrypt(void *private_key,
1626 				unsigned char *src,
1627 				SilcUInt32 src_len,
1628 				unsigned char *dst,
1629 				SilcUInt32 dst_size,
1630 				SilcUInt32 *ret_dst_len)
1631 {
1632   SilcSILCPrivateKey silc_privkey = private_key;
1633 
1634   if (!silc_privkey->pkcs->decrypt)
1635     return FALSE;
1636 
1637   return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
1638 				     src, src_len,
1639 				     dst, dst_size, ret_dst_len);
1640 }
1641 
1642 /* Signs as specified in SILC protocol specification */
1643 
silc_pkcs_silc_sign(void * private_key,unsigned char * src,SilcUInt32 src_len,unsigned char * signature,SilcUInt32 signature_size,SilcUInt32 * ret_signature_len,SilcBool compute_hash,SilcHash hash)1644 SilcBool silc_pkcs_silc_sign(void *private_key,
1645 			     unsigned char *src,
1646 			     SilcUInt32 src_len,
1647 			     unsigned char *signature,
1648 			     SilcUInt32 signature_size,
1649 			     SilcUInt32 *ret_signature_len,
1650 			     SilcBool compute_hash,
1651 			     SilcHash hash)
1652 {
1653   SilcSILCPrivateKey silc_privkey = private_key;
1654 
1655   if (!silc_privkey->pkcs->sign)
1656     return FALSE;
1657 
1658   return silc_privkey->pkcs->sign(silc_privkey->private_key,
1659 				  src, src_len,
1660 				  signature, signature_size,
1661 				  ret_signature_len, compute_hash, hash);
1662 }
1663 
1664 /* Verifies as specified in SILC protocol specification */
1665 
silc_pkcs_silc_verify(void * public_key,unsigned char * signature,SilcUInt32 signature_len,unsigned char * data,SilcUInt32 data_len,SilcHash hash)1666 SilcBool silc_pkcs_silc_verify(void *public_key,
1667 			       unsigned char *signature,
1668 			       SilcUInt32 signature_len,
1669 			       unsigned char *data,
1670 			       SilcUInt32 data_len,
1671 			       SilcHash hash)
1672 {
1673   SilcSILCPublicKey silc_pubkey = public_key;
1674 
1675   if (!silc_pubkey->pkcs->verify)
1676     return FALSE;
1677 
1678   return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
1679 				   signature, signature_len,
1680 				   data, data_len, hash);
1681 }
1682