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, 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, public_key->len);
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, totlen);
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;
403 buf = silc_buffer_alloc(data_len);
404 silc_buffer_pull_tail(buf, data_len);
405 silc_buffer_put(buf, data, data_len);
408 silc_buffer_unformat(buf,
409 SILC_STR_UI_INT(&totlen),
412 if (totlen != data_len) {
413 silc_buffer_free(buf);
417 /* Get algorithm name and identifier */
418 silc_buffer_pull(buf, 4);
419 silc_buffer_unformat(buf,
420 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
421 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
424 if (pkcs_len < 1 || identifier_len < 3 ||
425 pkcs_len + identifier_len > totlen)
428 /* See if we support this algorithm */
429 if (!silc_pkcs_is_supported(pkcs_name))
432 /* Protocol says that at least UN and HN must be provided as identifier,
434 if (!strstr(ident, "UN=") && !strstr(ident, "HN="))
437 /* Get key data. We assume that rest of the buffer is key data. */
438 silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
440 silc_buffer_unformat(buf,
441 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
444 /* Try to set the key. If this fails the key must be malformed. This
445 code assumes that the PKCS routine checks the format of the key. */
446 silc_pkcs_alloc(pkcs_name, &alg);
447 if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
452 *public_key = silc_calloc(1, sizeof(**public_key));
453 (*public_key)->len = totlen;
454 (*public_key)->name = pkcs_name;
455 (*public_key)->identifier = ident;
456 (*public_key)->pk = key_data;
457 (*public_key)->pk_len = key_len;
460 silc_buffer_free(buf);
465 silc_free(pkcs_name);
470 silc_buffer_free(buf);
474 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
477 silc_pkcs_private_key_encode(SilcPrivateKey private_key, unsigned int *len)
483 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
484 buf = silc_buffer_alloc(totlen);
485 silc_buffer_pull_tail(buf, totlen);
487 silc_buffer_format(buf,
488 SILC_STR_UI_SHORT(strlen(private_key->name)),
489 SILC_STR_UI32_STRING(private_key->name),
490 SILC_STR_UI_XNSTRING(private_key->prv,
491 private_key->prv_len),
496 ret = silc_calloc(buf->len, sizeof(*ret));
497 memcpy(ret, buf->data, buf->len);
498 silc_buffer_free(buf);
503 /* Encodes SILC private key. Returns the encoded data. */
506 silc_pkcs_private_key_data_encode(unsigned char *prv, unsigned int prv_len,
507 char *pkcs, unsigned int *len)
513 totlen = 2 + strlen(pkcs) + prv_len;
514 buf = silc_buffer_alloc(totlen);
515 silc_buffer_pull_tail(buf, totlen);
517 silc_buffer_format(buf,
518 SILC_STR_UI_SHORT(strlen(pkcs)),
519 SILC_STR_UI32_STRING(pkcs),
520 SILC_STR_UI_XNSTRING(prv, prv_len),
525 ret = silc_calloc(buf->len, sizeof(*ret));
526 memcpy(ret, buf->data, buf->len);
527 silc_buffer_free(buf);
532 /* Decodes SILC style public key. Returns TRUE if the decoding was
533 successful. Allocates new private key as well. */
535 int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
536 SilcPrivateKey *private_key)
540 unsigned short pkcs_len;
541 unsigned int key_len;
542 unsigned char *pkcs_name = NULL, *key_data = NULL;
544 buf = silc_buffer_alloc(data_len);
545 silc_buffer_pull_tail(buf, data_len);
546 silc_buffer_put(buf, data, data_len);
548 /* Get algorithm name and identifier */
549 silc_buffer_unformat(buf,
550 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
553 if (pkcs_len < 1 || pkcs_len > buf->truelen)
556 /* See if we support this algorithm */
557 if (!silc_pkcs_is_supported(pkcs_name))
560 /* Get key data. We assume that rest of the buffer is key data. */
561 silc_buffer_pull(buf, 2 + pkcs_len);
563 silc_buffer_unformat(buf,
564 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
567 /* Try to set the key. If this fails the key must be malformed. This
568 code assumes that the PKCS routine checks the format of the key. */
569 silc_pkcs_alloc(pkcs_name, &alg);
570 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
575 *private_key = silc_calloc(1, sizeof(**private_key));
576 (*private_key)->name = pkcs_name;
577 (*private_key)->prv = key_data;
578 (*private_key)->prv_len = key_len;
581 silc_buffer_free(buf);
586 silc_free(pkcs_name);
589 silc_buffer_free(buf);
593 /* Internal routine to save public key */
595 static int silc_pkcs_save_public_key_internal(char *filename,
597 unsigned int data_len,
598 unsigned int encoding)
604 case SILC_PKCS_FILE_BIN:
606 case SILC_PKCS_FILE_PEM:
607 data = silc_encode_pem_file(data, data_len);
608 data_len = strlen(data);
612 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
613 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
614 buf = silc_buffer_alloc(len);
615 silc_buffer_pull_tail(buf, len);
617 silc_buffer_format(buf,
618 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
619 SILC_STR_UI_XNSTRING(data, data_len),
620 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
624 if (silc_file_write(filename, buf->data, buf->len)) {
625 silc_buffer_free(buf);
629 silc_buffer_free(buf);
633 /* Saves public key into file */
635 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
636 unsigned int encoding)
639 unsigned int data_len;
641 data = silc_pkcs_public_key_encode(public_key, &data_len);
642 return silc_pkcs_save_public_key_internal(filename, data, data_len,
646 /* Saves public key into file */
648 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
649 unsigned int data_len,
650 unsigned int encoding)
652 return silc_pkcs_save_public_key_internal(filename, data, data_len,
656 /* Internal routine to save private key. */
658 static int silc_pkcs_save_private_key_internal(char *filename,
660 unsigned int data_len,
661 unsigned int encoding)
667 case SILC_PKCS_FILE_BIN:
669 case SILC_PKCS_FILE_PEM:
670 data = silc_encode_pem_file(data, data_len);
671 data_len = strlen(data);
675 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
676 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
677 buf = silc_buffer_alloc(len);
678 silc_buffer_pull_tail(buf, len);
680 silc_buffer_format(buf,
681 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
682 SILC_STR_UI_XNSTRING(data, data_len),
683 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
686 /* Save into a file */
687 if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
688 silc_buffer_free(buf);
692 silc_buffer_free(buf);
696 /* Saves private key into file. */
697 /* XXX The buffer should be encrypted if passphrase is provided. */
699 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
700 unsigned char *passphrase,
701 unsigned int encoding)
704 unsigned int data_len;
706 data = silc_pkcs_private_key_encode(private_key, &data_len);
707 return silc_pkcs_save_private_key_internal(filename, data, data_len,
711 /* Saves private key into file. */
712 /* XXX The buffer should be encrypted if passphrase is provided. */
714 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
715 unsigned int data_len,
716 unsigned char *passphrase,
717 unsigned int encoding)
719 return silc_pkcs_save_private_key_internal(filename, data, data_len,
723 /* Loads public key from file and allocates new public key. Returns TRUE
724 is loading was successful. */
726 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
727 unsigned int encoding)
729 unsigned char *cp, *old, *data, byte;
730 unsigned int i, data_len, len;
732 old = data = silc_file_read(filename, &data_len);
736 /* Check start of file and remove header from the data. */
737 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
739 for (i = 0; i < len; i++) {
742 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
743 memset(old, 0, data_len);
749 /* Decode public key */
751 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
752 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
755 case SILC_PKCS_FILE_BIN:
757 case SILC_PKCS_FILE_PEM:
758 data = silc_decode_pem(data, len, &len);
762 if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
763 memset(old, 0, data_len);
769 memset(old, 0, data_len);
774 /* Load private key from file and allocates new private key. Returns TRUE
775 if loading was successful. */
776 /* XXX Should support encrypted private key files */
778 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
779 unsigned int encoding)
781 unsigned char *cp, *old, *data, byte;
782 unsigned int i, data_len, len;
784 old = data = silc_file_read(filename, &data_len);
788 /* Check start of file and remove header from the data. */
789 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
791 for (i = 0; i < len; i++) {
794 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
795 memset(old, 0, data_len);
801 /* Decode private key */
803 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
804 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
807 case SILC_PKCS_FILE_BIN:
809 case SILC_PKCS_FILE_PEM:
810 data = silc_decode_pem(data, len, &len);
814 if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
815 memset(old, 0, data_len);
821 memset(old, 0, data_len);