5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
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.
22 #include "silcincludes.h"
26 /* List of all PKCS's in SILC. PKCS's don't support SIM's thus
27 only static declarations are possible. XXX: I hope this to change
29 SilcPKCSObject silc_pkcs_list[] =
31 { "rsa", &silc_rsa_data_context,
32 silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
33 silc_rsa_get_private_key, silc_rsa_set_public_key,
34 silc_rsa_set_private_key, silc_rsa_context_len,
35 silc_rsa_data_context_len, silc_rsa_set_arg,
36 silc_rsa_encrypt, silc_rsa_decrypt,
37 silc_rsa_sign, silc_rsa_verify },
39 { NULL, NULL, NULL, NULL, NULL,
40 NULL, NULL, NULL, NULL, NULL, NULL }
43 /* Allocates a new SilcPKCS object. The new allocated object is returned
44 to the 'new_pkcs' argument. This function also initializes the data
45 context structure. Function returns 1 on success and 0 on error.
48 int silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
52 SILC_LOG_DEBUG(("Allocating new PKCS object"));
54 for (i = 0; silc_pkcs_list[i].name; i++) {
55 if (!strcmp(silc_pkcs_list[i].name, name))
59 if (silc_pkcs_list[i].name == NULL)
62 *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
64 /* Set the pointers */
65 (*new_pkcs)->pkcs = &silc_pkcs_list[i];
66 (*new_pkcs)->pkcs->data_context =
67 silc_calloc(1, (*new_pkcs)->pkcs->data_context_len());
68 (*new_pkcs)->context = silc_calloc(1, (*new_pkcs)->pkcs->context_len());
69 (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
74 /* Free's the PKCS object */
76 void silc_pkcs_free(SilcPKCS pkcs)
79 silc_free(pkcs->context);
82 /* Return TRUE if PKCS algorithm `name' is supported. */
84 int silc_pkcs_is_supported(const unsigned char *name)
88 for (i = 0; silc_pkcs_list[i].name; i++) {
89 if (!strcmp(silc_pkcs_list[i].name, name))
96 /* Returns comma separated list of supported PKCS algorithms */
98 char *silc_pkcs_get_supported()
104 for (i = 0; silc_pkcs_list[i].name; i++) {
105 len += strlen(silc_pkcs_list[i].name);
106 list = silc_realloc(list, len + 1);
108 memcpy(list + (len - strlen(silc_pkcs_list[i].name)),
109 silc_pkcs_list[i].name, strlen(silc_pkcs_list[i].name));
110 memcpy(list + len, ",", 1);
119 /* Returns the length of the key */
121 unsigned int silc_pkcs_get_key_len(SilcPKCS self)
123 return self->key_len;
126 /* Returns SILC style public key */
128 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, unsigned int *len)
130 return pkcs->pkcs->get_public_key(pkcs->context, len);
133 /* Returns SILC style private key */
135 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, unsigned int *len)
137 return pkcs->pkcs->get_private_key(pkcs->context, len);
140 /* Sets public key from SilcPublicKey. */
142 int silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
144 return pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
148 /* Sets public key from data. */
150 int silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
153 return pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
156 /* Sets private key from SilcPrivateKey. */
158 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
160 return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
161 private_key->prv_len);
164 /* Sets private key from data. */
166 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
167 unsigned int prv_len)
169 return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
172 /* Encodes and returns SILC public key identifier. If some of the
173 arguments is NULL those are not encoded into the identifier string.
174 Protocol says that at least username and host must be provided. */
176 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
177 char *email, char *org, char *country)
181 unsigned int len, tlen = 0;
183 if (!username || !host)
186 len = (username ? strlen(username) : 0) +
187 (host ? strlen(host) : 0) +
188 (realname ? strlen(realname) : 0) +
189 (email ? strlen(email) : 0) +
190 (org ? strlen(org) : 0) +
191 (country ? strlen(country) : 0);
196 len += 3 + 5 + 5 + 4 + 4 + 4;
197 buf = silc_buffer_alloc(len);
198 silc_buffer_pull_tail(buf, len);
201 silc_buffer_format(buf,
202 SILC_STR_UI32_STRING("UN="),
203 SILC_STR_UI32_STRING(username),
205 silc_buffer_pull(buf, 3 + strlen(username));
206 tlen = 3 + strlen(username);
210 silc_buffer_format(buf,
211 SILC_STR_UI32_STRING(", "),
212 SILC_STR_UI32_STRING("HN="),
213 SILC_STR_UI32_STRING(host),
215 silc_buffer_pull(buf, 5 + strlen(host));
216 tlen += 5 + strlen(host);
220 silc_buffer_format(buf,
221 SILC_STR_UI32_STRING(", "),
222 SILC_STR_UI32_STRING("RN="),
223 SILC_STR_UI32_STRING(realname),
225 silc_buffer_pull(buf, 5 + strlen(realname));
226 tlen += 5 + strlen(realname);
230 silc_buffer_format(buf,
231 SILC_STR_UI32_STRING(", "),
232 SILC_STR_UI32_STRING("E="),
233 SILC_STR_UI32_STRING(email),
235 silc_buffer_pull(buf, 4 + strlen(email));
236 tlen += 4 + strlen(email);
240 silc_buffer_format(buf,
241 SILC_STR_UI32_STRING(", "),
242 SILC_STR_UI32_STRING("O="),
243 SILC_STR_UI32_STRING(org),
245 silc_buffer_pull(buf, 4 + strlen(org));
246 tlen += 4 + strlen(org);
250 silc_buffer_format(buf,
251 SILC_STR_UI32_STRING(", "),
252 SILC_STR_UI32_STRING("C="),
253 SILC_STR_UI32_STRING(country),
255 silc_buffer_pull(buf, 4 + strlen(country));
256 tlen += 4 + strlen(country);
259 silc_buffer_push(buf, buf->data - buf->head);
260 identifier = silc_calloc(tlen + 1, sizeof(*identifier));
261 memcpy(identifier, buf->data, tlen);
262 silc_buffer_free(buf);
267 /* Allocates SILC style public key formed from sent arguments. All data
270 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
274 SilcPublicKey public_key;
276 public_key = silc_calloc(1, sizeof(*public_key));
277 public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
278 public_key->name = strdup(name);
279 public_key->identifier = strdup(identifier);
280 public_key->pk_len = pk_len;
281 public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
282 memcpy(public_key->pk, pk, pk_len);
287 /* Free's public key */
289 void silc_pkcs_public_key_free(SilcPublicKey public_key)
292 silc_free(public_key->name);
293 silc_free(public_key->identifier);
294 silc_free(public_key->pk);
295 silc_free(public_key);
299 /* Allocates SILC private key formed from sent arguments. All data is
302 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
303 unsigned int prv_len)
305 SilcPrivateKey private_key;
307 private_key = silc_calloc(1, sizeof(*private_key));
308 private_key->name = strdup(name);
309 private_key->prv_len = prv_len;
310 private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
311 memcpy(private_key->prv, prv, prv_len);
316 /* Free's private key */
318 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
321 silc_free(private_key->name);
322 silc_free(private_key->prv);
323 silc_free(private_key);
327 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
331 silc_pkcs_public_key_encode(SilcPublicKey public_key, unsigned int *len)
336 buf = silc_buffer_alloc(public_key->len);
337 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
339 silc_buffer_format(buf,
340 SILC_STR_UI_INT(public_key->len),
341 SILC_STR_UI_SHORT(strlen(public_key->name)),
342 SILC_STR_UI32_STRING(public_key->name),
343 SILC_STR_UI_SHORT(strlen(public_key->identifier)),
344 SILC_STR_UI32_STRING(public_key->identifier),
345 SILC_STR_UI_XNSTRING(public_key->pk,
349 *len = public_key->len;
351 ret = silc_calloc(buf->len, sizeof(*ret));
352 memcpy(ret, buf->data, buf->len);
353 silc_buffer_free(buf);
358 /* Encodes SILC style public key. Returns the encoded data. */
361 silc_pkcs_public_key_data_encode(unsigned char *pk, unsigned int pk_len,
362 char *pkcs, char *identifier,
369 totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
370 buf = silc_buffer_alloc(totlen);
371 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
373 silc_buffer_format(buf,
374 SILC_STR_UI_INT(totlen),
375 SILC_STR_UI_SHORT(strlen(pkcs)),
376 SILC_STR_UI32_STRING(pkcs),
377 SILC_STR_UI_SHORT(strlen(identifier)),
378 SILC_STR_UI32_STRING(identifier),
379 SILC_STR_UI_XNSTRING(pk, pk_len),
384 ret = silc_calloc(buf->len, sizeof(*ret));
385 memcpy(ret, buf->data, buf->len);
386 silc_buffer_free(buf);
391 /* Decodes SILC style public key. Returns TRUE if the decoding was
392 successful. Allocates new public key as well. */
394 int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
395 SilcPublicKey *public_key)
399 unsigned short pkcs_len, identifier_len;
400 unsigned int totlen, key_len;
401 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
404 buf = silc_buffer_alloc(data_len);
405 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
406 silc_buffer_put(buf, data, data_len);
409 ret = silc_buffer_unformat(buf,
410 SILC_STR_UI_INT(&totlen),
413 silc_buffer_free(buf);
417 if (totlen != data_len) {
418 silc_buffer_free(buf);
422 /* Get algorithm name and identifier */
423 silc_buffer_pull(buf, 4);
425 silc_buffer_unformat(buf,
426 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
427 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
432 if (pkcs_len < 1 || identifier_len < 3 ||
433 pkcs_len + identifier_len > totlen)
436 /* See if we support this algorithm */
437 if (!silc_pkcs_is_supported(pkcs_name))
440 /* Protocol says that at least UN and HN must be provided as identifier,
442 if (!strstr(ident, "UN=") && !strstr(ident, "HN="))
445 /* Get key data. We assume that rest of the buffer is key data. */
446 silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
448 ret = silc_buffer_unformat(buf,
449 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
454 /* Try to set the key. If this fails the key must be malformed. This
455 code assumes that the PKCS routine checks the format of the key. */
456 silc_pkcs_alloc(pkcs_name, &alg);
457 if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
462 *public_key = silc_calloc(1, sizeof(**public_key));
463 (*public_key)->len = totlen;
464 (*public_key)->name = pkcs_name;
465 (*public_key)->identifier = ident;
466 (*public_key)->pk = key_data;
467 (*public_key)->pk_len = key_len;
470 silc_buffer_free(buf);
475 silc_free(pkcs_name);
480 silc_buffer_free(buf);
484 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
487 silc_pkcs_private_key_encode(SilcPrivateKey private_key, unsigned int *len)
493 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
494 buf = silc_buffer_alloc(totlen);
495 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
497 silc_buffer_format(buf,
498 SILC_STR_UI_SHORT(strlen(private_key->name)),
499 SILC_STR_UI32_STRING(private_key->name),
500 SILC_STR_UI_XNSTRING(private_key->prv,
501 private_key->prv_len),
506 ret = silc_calloc(buf->len, sizeof(*ret));
507 memcpy(ret, buf->data, buf->len);
508 silc_buffer_free(buf);
513 /* Encodes SILC private key. Returns the encoded data. */
516 silc_pkcs_private_key_data_encode(unsigned char *prv, unsigned int prv_len,
517 char *pkcs, unsigned int *len)
523 totlen = 2 + strlen(pkcs) + prv_len;
524 buf = silc_buffer_alloc(totlen);
525 silc_buffer_pull_tail(buf, totlen);
527 silc_buffer_format(buf,
528 SILC_STR_UI_SHORT(strlen(pkcs)),
529 SILC_STR_UI32_STRING(pkcs),
530 SILC_STR_UI_XNSTRING(prv, prv_len),
535 ret = silc_calloc(buf->len, sizeof(*ret));
536 memcpy(ret, buf->data, buf->len);
537 silc_buffer_free(buf);
542 /* Decodes SILC style public key. Returns TRUE if the decoding was
543 successful. Allocates new private key as well. */
545 int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
546 SilcPrivateKey *private_key)
550 unsigned short pkcs_len;
551 unsigned int key_len;
552 unsigned char *pkcs_name = NULL, *key_data = NULL;
555 buf = silc_buffer_alloc(data_len);
556 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
557 silc_buffer_put(buf, data, data_len);
559 /* Get algorithm name and identifier */
561 silc_buffer_unformat(buf,
562 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
567 if (pkcs_len < 1 || pkcs_len > buf->truelen)
570 /* See if we support this algorithm */
571 if (!silc_pkcs_is_supported(pkcs_name))
574 /* Get key data. We assume that rest of the buffer is key data. */
575 silc_buffer_pull(buf, 2 + pkcs_len);
577 ret = silc_buffer_unformat(buf,
578 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
583 /* Try to set the key. If this fails the key must be malformed. This
584 code assumes that the PKCS routine checks the format of the key. */
585 silc_pkcs_alloc(pkcs_name, &alg);
586 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
591 *private_key = silc_calloc(1, sizeof(**private_key));
592 (*private_key)->name = pkcs_name;
593 (*private_key)->prv = key_data;
594 (*private_key)->prv_len = key_len;
597 silc_buffer_free(buf);
602 silc_free(pkcs_name);
605 silc_buffer_free(buf);
609 /* Internal routine to save public key */
611 static int silc_pkcs_save_public_key_internal(char *filename,
613 unsigned int data_len,
614 unsigned int encoding)
620 case SILC_PKCS_FILE_BIN:
622 case SILC_PKCS_FILE_PEM:
623 data = silc_encode_pem_file(data, data_len);
624 data_len = strlen(data);
628 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
629 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
630 buf = silc_buffer_alloc(len);
631 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
633 silc_buffer_format(buf,
634 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
635 SILC_STR_UI_XNSTRING(data, data_len),
636 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
640 if (silc_file_write(filename, buf->data, buf->len)) {
641 silc_buffer_free(buf);
645 silc_buffer_free(buf);
649 /* Saves public key into file */
651 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
652 unsigned int encoding)
655 unsigned int data_len;
657 data = silc_pkcs_public_key_encode(public_key, &data_len);
658 return silc_pkcs_save_public_key_internal(filename, data, data_len,
662 /* Saves public key into file */
664 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
665 unsigned int data_len,
666 unsigned int encoding)
668 return silc_pkcs_save_public_key_internal(filename, data, data_len,
672 /* Internal routine to save private key. */
674 static int silc_pkcs_save_private_key_internal(char *filename,
676 unsigned int data_len,
677 unsigned int encoding)
683 case SILC_PKCS_FILE_BIN:
685 case SILC_PKCS_FILE_PEM:
686 data = silc_encode_pem_file(data, data_len);
687 data_len = strlen(data);
691 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
692 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
693 buf = silc_buffer_alloc(len);
694 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
696 silc_buffer_format(buf,
697 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
698 SILC_STR_UI_XNSTRING(data, data_len),
699 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
702 /* Save into a file */
703 if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
704 silc_buffer_free(buf);
708 silc_buffer_free(buf);
712 /* Saves private key into file. */
713 /* XXX The buffer should be encrypted if passphrase is provided. */
715 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
716 unsigned char *passphrase,
717 unsigned int encoding)
720 unsigned int data_len;
722 data = silc_pkcs_private_key_encode(private_key, &data_len);
723 return silc_pkcs_save_private_key_internal(filename, data, data_len,
727 /* Saves private key into file. */
728 /* XXX The buffer should be encrypted if passphrase is provided. */
730 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
731 unsigned int data_len,
732 unsigned char *passphrase,
733 unsigned int encoding)
735 return silc_pkcs_save_private_key_internal(filename, data, data_len,
739 /* Loads public key from file and allocates new public key. Returns TRUE
740 is loading was successful. */
742 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
743 unsigned int encoding)
745 unsigned char *cp, *old, *data, byte;
746 unsigned int i, data_len, len;
748 old = data = silc_file_read(filename, &data_len);
752 /* Check start of file and remove header from the data. */
753 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
755 for (i = 0; i < len; i++) {
758 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
759 memset(old, 0, data_len);
765 /* Decode public key */
767 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
768 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
771 case SILC_PKCS_FILE_BIN:
773 case SILC_PKCS_FILE_PEM:
774 data = silc_decode_pem(data, len, &len);
778 if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
779 memset(old, 0, data_len);
785 memset(old, 0, data_len);
790 /* Load private key from file and allocates new private key. Returns TRUE
791 if loading was successful. */
792 /* XXX Should support encrypted private key files */
794 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
795 unsigned int encoding)
797 unsigned char *cp, *old, *data, byte;
798 unsigned int i, data_len, len;
800 old = data = silc_file_read(filename, &data_len);
804 /* Check start of file and remove header from the data. */
805 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
807 for (i = 0; i < len; i++) {
810 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
811 memset(old, 0, data_len);
817 /* Decode private key */
819 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
820 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
823 case SILC_PKCS_FILE_BIN:
825 case SILC_PKCS_FILE_PEM:
826 data = silc_decode_pem(data, len, &len);
830 if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
831 memset(old, 0, data_len);
837 memset(old, 0, data_len);