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.
21 #include "silcincludes.h"
25 /* List of all PKCS's in SILC. PKCS's don't support SIM's thus
26 only static declarations are possible. XXX: I hope this to change
28 SilcPKCSObject silc_pkcs_list[] =
30 { "rsa", &silc_rsa_data_context,
31 silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
32 silc_rsa_get_private_key, silc_rsa_set_public_key,
33 silc_rsa_set_private_key, silc_rsa_context_len,
34 silc_rsa_data_context_len, silc_rsa_set_arg,
35 silc_rsa_encrypt, silc_rsa_decrypt,
36 silc_rsa_sign, silc_rsa_verify },
38 { NULL, NULL, NULL, NULL, NULL,
39 NULL, NULL, NULL, NULL, NULL, NULL }
42 /* Allocates a new SilcPKCS object. The new allocated object is returned
43 to the 'new_pkcs' argument. This function also initializes the data
44 context structure. Function returns 1 on success and 0 on error.
47 int silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
51 SILC_LOG_DEBUG(("Allocating new PKCS object"));
53 for (i = 0; silc_pkcs_list[i].name; i++) {
54 if (!strcmp(silc_pkcs_list[i].name, name))
58 if (silc_pkcs_list[i].name == NULL)
61 *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
63 /* Set the pointers */
64 (*new_pkcs)->pkcs = &silc_pkcs_list[i];
65 (*new_pkcs)->pkcs->data_context =
66 silc_calloc(1, (*new_pkcs)->pkcs->data_context_len());
67 (*new_pkcs)->context = silc_calloc(1, (*new_pkcs)->pkcs->context_len());
68 (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
73 /* Free's the PKCS object */
75 void silc_pkcs_free(SilcPKCS pkcs)
78 silc_free(pkcs->context);
81 /* Return TRUE if PKCS algorithm `name' is supported. */
83 int silc_pkcs_is_supported(const unsigned char *name)
87 for (i = 0; silc_pkcs_list[i].name; i++) {
88 if (!strcmp(silc_pkcs_list[i].name, name))
95 /* Returns comma separated list of supported PKCS algorithms */
97 char *silc_pkcs_get_supported()
103 for (i = 0; silc_pkcs_list[i].name; i++) {
104 len += strlen(silc_pkcs_list[i].name);
105 list = silc_realloc(list, len + 1);
107 memcpy(list + (len - strlen(silc_pkcs_list[i].name)),
108 silc_pkcs_list[i].name, strlen(silc_pkcs_list[i].name));
109 memcpy(list + len, ",", 1);
118 /* Returns the length of the key */
120 unsigned int silc_pkcs_get_key_len(SilcPKCS self)
122 return self->key_len;
125 /* Returns SILC style public key */
127 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, unsigned int *len)
129 return pkcs->pkcs->get_public_key(pkcs->context, len);
132 /* Returns SILC style private key */
134 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, unsigned int *len)
136 return pkcs->pkcs->get_private_key(pkcs->context, len);
139 /* Sets public key */
141 int silc_pkcs_set_public_key(SilcPKCS pkcs, unsigned char *pk,
144 return pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
147 /* Sets private key */
149 int silc_pkcs_set_private_key(SilcPKCS pkcs, unsigned char *prv,
150 unsigned int prv_len)
152 return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
155 /* Encodes and returns SILC public key identifier. If some of the
156 arguments as NULL those are not encoded into the identifier string.
157 Protocol says that at least username and host must be provided. */
159 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
160 char *email, char *org, char *country)
164 unsigned int len, tlen = 0;
166 if (!username || !host)
169 len = (username ? strlen(username) : 0) +
170 (host ? strlen(host) : 0) +
171 (realname ? strlen(realname) : 0) +
172 (email ? strlen(email) : 0) +
173 (org ? strlen(org) : 0) +
174 (country ? strlen(country) : 0);
179 len += 3 + 5 + 5 + 4 + 4 + 4;
180 buf = silc_buffer_alloc(len);
181 silc_buffer_pull_tail(buf, len);
184 silc_buffer_format(buf,
185 SILC_STR_UI32_STRING("UN="),
186 SILC_STR_UI32_STRING(username),
188 silc_buffer_pull(buf, 3 + strlen(username));
189 tlen = 3 + strlen(username);
193 silc_buffer_format(buf,
194 SILC_STR_UI32_STRING(", "),
195 SILC_STR_UI32_STRING("HN="),
196 SILC_STR_UI32_STRING(host),
198 silc_buffer_pull(buf, 5 + strlen(host));
199 tlen += 5 + strlen(host);
203 silc_buffer_format(buf,
204 SILC_STR_UI32_STRING(", "),
205 SILC_STR_UI32_STRING("RN="),
206 SILC_STR_UI32_STRING(realname),
208 silc_buffer_pull(buf, 5 + strlen(realname));
209 tlen += 5 + strlen(realname);
213 silc_buffer_format(buf,
214 SILC_STR_UI32_STRING(", "),
215 SILC_STR_UI32_STRING("E="),
216 SILC_STR_UI32_STRING(email),
218 silc_buffer_pull(buf, 4 + strlen(email));
219 tlen += 4 + strlen(email);
223 silc_buffer_format(buf,
224 SILC_STR_UI32_STRING(", "),
225 SILC_STR_UI32_STRING("O="),
226 SILC_STR_UI32_STRING(org),
228 silc_buffer_pull(buf, 4 + strlen(org));
229 tlen += 4 + strlen(org);
233 silc_buffer_format(buf,
234 SILC_STR_UI32_STRING(", "),
235 SILC_STR_UI32_STRING("C="),
236 SILC_STR_UI32_STRING(country),
238 silc_buffer_pull(buf, 4 + strlen(country));
239 tlen += 4 + strlen(country);
242 silc_buffer_push(buf, buf->data - buf->head);
243 identifier = silc_calloc(tlen, sizeof(*identifier));
244 memcpy(identifier, buf->data, tlen);
245 silc_buffer_free(buf);
250 /* Allocates SILC style public key formed from sent arguments. All data
253 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
257 SilcPublicKey public_key;
259 public_key = silc_calloc(1, sizeof(*public_key));
260 public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
261 public_key->name = strdup(name);
262 public_key->identifier = strdup(identifier);
263 public_key->pk_len = pk_len;
264 public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
265 memcpy(public_key->pk, pk, pk_len);
270 /* Free's public key */
272 void silc_pkcs_public_key_free(SilcPublicKey public_key)
275 silc_free(public_key->name);
276 silc_free(public_key->identifier);
277 silc_free(public_key->pk);
278 silc_free(public_key);
282 /* Allocates SILC private key formed from sent arguments. All data is
285 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
286 unsigned int prv_len)
288 SilcPrivateKey private_key;
290 private_key = silc_calloc(1, sizeof(*private_key));
291 private_key->name = strdup(name);
292 private_key->prv_len = prv_len;
293 private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
294 memcpy(private_key->prv, prv, prv_len);
299 /* Free's private key */
301 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
304 silc_free(private_key->name);
305 silc_free(private_key->prv);
306 silc_free(private_key);
310 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
314 silc_pkcs_public_key_encode(SilcPublicKey public_key, unsigned int *len)
319 buf = silc_buffer_alloc(public_key->len);
320 silc_buffer_pull_tail(buf, public_key->len);
322 silc_buffer_format(buf,
323 SILC_STR_UI_INT(public_key->len),
324 SILC_STR_UI_SHORT(strlen(public_key->name)),
325 SILC_STR_UI32_STRING(public_key->name),
326 SILC_STR_UI_SHORT(strlen(public_key->identifier)),
327 SILC_STR_UI32_STRING(public_key->identifier),
328 SILC_STR_UI_XNSTRING(public_key->pk,
332 *len = public_key->len;
334 ret = silc_calloc(buf->len, sizeof(*ret));
335 memcpy(ret, buf->data, buf->len);
336 silc_buffer_free(buf);
341 /* Encodes SILC style public key. Returns the encoded data. */
344 silc_pkcs_public_key_data_encode(unsigned char *pk, unsigned int pk_len,
345 char *pkcs, char *identifier,
352 totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
353 buf = silc_buffer_alloc(totlen);
354 silc_buffer_pull_tail(buf, totlen);
356 silc_buffer_format(buf,
357 SILC_STR_UI_INT(totlen),
358 SILC_STR_UI_SHORT(strlen(pkcs)),
359 SILC_STR_UI32_STRING(pkcs),
360 SILC_STR_UI_SHORT(strlen(identifier)),
361 SILC_STR_UI32_STRING(identifier),
362 SILC_STR_UI_XNSTRING(pk, pk_len),
367 ret = silc_calloc(buf->len, sizeof(*ret));
368 memcpy(ret, buf->data, buf->len);
369 silc_buffer_free(buf);
374 /* Decodes SILC style public key. Returns TRUE if the decoding was
375 successful. Allocates new public key as well. */
377 int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
378 SilcPublicKey *public_key)
382 unsigned short pkcs_len, identifier_len;
383 unsigned int totlen, key_len;
384 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
386 buf = silc_buffer_alloc(data_len);
387 silc_buffer_pull_tail(buf, data_len);
388 silc_buffer_put(buf, data, data_len);
391 silc_buffer_unformat(buf,
392 SILC_STR_UI_INT(&totlen),
395 if (totlen != data_len) {
396 silc_buffer_free(buf);
400 /* Get algorithm name and identifier */
401 silc_buffer_pull(buf, 4);
402 silc_buffer_unformat(buf,
403 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
404 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
407 if (pkcs_len < 1 || identifier_len < 3 ||
408 pkcs_len + identifier_len > totlen)
411 /* See if we support this algorithm */
412 if (!silc_pkcs_is_supported(pkcs_name))
415 /* Protocol says that at least UN and HN must be provided as identifier,
417 if (!strstr(ident, "UN=") && !strstr(ident, "HN="))
420 /* Get key data. We assume that rest of the buffer is key data. */
421 silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
423 silc_buffer_unformat(buf,
424 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
427 /* Try to set the key. If this fails the key must be malformed. This
428 code assumes that the PKCS routine checks the format of the key. */
429 silc_pkcs_alloc(pkcs_name, &alg);
430 if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
435 *public_key = silc_calloc(1, sizeof(**public_key));
436 (*public_key)->len = totlen;
437 (*public_key)->name = pkcs_name;
438 (*public_key)->identifier = ident;
439 (*public_key)->pk = key_data;
440 (*public_key)->pk_len = key_len;
443 silc_buffer_free(buf);
448 silc_free(pkcs_name);
453 silc_buffer_free(buf);
457 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
460 silc_pkcs_private_key_encode(SilcPrivateKey private_key, unsigned int *len)
466 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
467 buf = silc_buffer_alloc(totlen);
468 silc_buffer_pull_tail(buf, totlen);
470 silc_buffer_format(buf,
471 SILC_STR_UI_SHORT(strlen(private_key->name)),
472 SILC_STR_UI32_STRING(private_key->name),
473 SILC_STR_UI_XNSTRING(private_key->prv,
474 private_key->prv_len),
479 ret = silc_calloc(buf->len, sizeof(*ret));
480 memcpy(ret, buf->data, buf->len);
481 silc_buffer_free(buf);
486 /* Encodes SILC private key. Returns the encoded data. */
489 silc_pkcs_private_key_data_encode(unsigned char *prv, unsigned int prv_len,
490 char *pkcs, unsigned int *len)
496 totlen = 2 + strlen(pkcs) + prv_len;
497 buf = silc_buffer_alloc(totlen);
498 silc_buffer_pull_tail(buf, totlen);
500 silc_buffer_format(buf,
501 SILC_STR_UI_SHORT(strlen(pkcs)),
502 SILC_STR_UI32_STRING(pkcs),
503 SILC_STR_UI_XNSTRING(prv, prv_len),
508 ret = silc_calloc(buf->len, sizeof(*ret));
509 memcpy(ret, buf->data, buf->len);
510 silc_buffer_free(buf);
515 /* Decodes SILC style public key. Returns TRUE if the decoding was
516 successful. Allocates new private key as well. */
518 int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
519 SilcPrivateKey *private_key)
523 unsigned short pkcs_len;
524 unsigned int key_len;
525 unsigned char *pkcs_name = NULL, *key_data = NULL;
527 buf = silc_buffer_alloc(data_len);
528 silc_buffer_pull_tail(buf, data_len);
529 silc_buffer_put(buf, data, data_len);
531 /* Get algorithm name and identifier */
532 silc_buffer_unformat(buf,
533 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
536 if (pkcs_len < 1 || pkcs_len > buf->truelen)
539 /* See if we support this algorithm */
540 if (!silc_pkcs_is_supported(pkcs_name))
543 /* Get key data. We assume that rest of the buffer is key data. */
544 silc_buffer_pull(buf, 2 + pkcs_len);
546 silc_buffer_unformat(buf,
547 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
550 /* Try to set the key. If this fails the key must be malformed. This
551 code assumes that the PKCS routine checks the format of the key. */
552 silc_pkcs_alloc(pkcs_name, &alg);
553 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
558 *private_key = silc_calloc(1, sizeof(**private_key));
559 (*private_key)->name = pkcs_name;
560 (*private_key)->prv = key_data;
561 (*private_key)->prv_len = key_len;
564 silc_buffer_free(buf);
569 silc_free(pkcs_name);
572 silc_buffer_free(buf);
576 /* Internal routine to save public key */
578 static int silc_pkcs_save_public_key_internal(char *filename,
580 unsigned int data_len)
585 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
586 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
587 buf = silc_buffer_alloc(len);
588 silc_buffer_pull_tail(buf, len);
590 silc_buffer_format(buf,
591 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
592 SILC_STR_UI_XNSTRING(data, data_len),
593 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
596 /* Save into a file */
597 if (silc_file_write(filename, buf->data, buf->len)) {
598 memset(data, 0, data_len);
600 silc_buffer_free(buf);
604 memset(data, 0, data_len);
606 silc_buffer_free(buf);
610 /* Saves public key into file */
611 /* XXX encoding should be defined (PEM or binary). */
613 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key)
616 unsigned int data_len;
618 data = silc_pkcs_public_key_encode(public_key, &data_len);
619 return silc_pkcs_save_public_key_internal(filename, data, data_len);
622 /* Saves public key into file */
623 /* XXX encoding should be defined (PEM or binary). */
625 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
626 unsigned int data_len)
628 return silc_pkcs_save_public_key_internal(filename, data, data_len);
631 /* Internal routine to save private key. */
633 static int silc_pkcs_save_private_key_internal(char *filename,
635 unsigned int data_len)
640 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
641 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
642 buf = silc_buffer_alloc(len);
643 silc_buffer_pull_tail(buf, len);
645 silc_buffer_format(buf,
646 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
647 SILC_STR_UI_XNSTRING(data, data_len),
648 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
651 /* Save into a file */
652 if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
653 memset(data, 0, data_len);
655 silc_buffer_free(buf);
659 memset(data, 0, data_len);
661 silc_buffer_free(buf);
665 /* Saves private key into file. */
666 /* XXX The buffer should be encrypted if passphrase is provided. */
667 /* XXX encoding should be defined (PEM or binary). */
669 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
670 unsigned char *passphrase)
673 unsigned int data_len;
675 data = silc_pkcs_private_key_encode(private_key, &data_len);
676 return silc_pkcs_save_private_key_internal(filename, data, data_len);
679 /* Saves private key into file. */
680 /* XXX The buffer should be encrypted if passphrase is provided. */
681 /* XXX encoding should be defined (PEM or binary). */
683 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
684 unsigned int data_len,
685 unsigned char *passphrase)
687 return silc_pkcs_save_private_key_internal(filename, data, data_len);
690 /* Loads public key from file and allocates new public key. Returns TRUE
691 is loading was successful. */
692 /* XXX Encoding should be defined. */
694 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key)
696 unsigned char *cp, *old, *data, byte;
697 unsigned int i, data_len, len;
699 old = data = silc_file_read(filename, &data_len);
703 /* Check start of file and remove header from the data. */
704 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
706 for (i = 0; i < len; i++) {
709 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
710 memset(old, 0, data_len);
716 /* Decode public key */
718 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
719 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
720 if (!silc_pkcs_public_key_decode(data, len, public_key)) {
721 memset(old, 0, data_len);
727 memset(old, 0, data_len);
732 /* Load private key from file and allocates new private key. Returns TRUE
733 if loading was successful. */
734 /* XXX Encoding should be defined. */
735 /* XXX Should support encrypted private key files */
737 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key)
739 unsigned char *cp, *old, *data, byte;
740 unsigned int i, data_len, len;
742 old = data = silc_file_read(filename, &data_len);
746 /* Check start of file and remove header from the data. */
747 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
749 for (i = 0; i < len; i++) {
752 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
753 memset(old, 0, data_len);
759 /* Decode private key */
761 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
762 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
763 if (!silc_pkcs_private_key_decode(data, len, private_key)) {
764 memset(old, 0, data_len);
770 memset(old, 0, data_len);