Added OpenPGP library to lib/silcpgp
[crypto.git] / lib / silcpgp / silcpgp_pkcs.c
1 /*
2
3   silcpgp_pkcs.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2007 - 2008 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include "silccrypto.h"
21 #include "rsa.h"
22 #include "dsa.h"
23
24 /**************************** OpenPGP PKCS API ******************************/
25
26 /* Get algorithm context */
27
28 SILC_PKCS_GET_ALGORITHM(silc_pkcs_pgp_get_algorithm)
29 {
30   SilcPGPPublicKey pubkey = public_key;
31   return pubkey->pkcs;
32 }
33
34 /* Import PGP public key file */
35
36 SILC_PKCS_IMPORT_PUBLIC_KEY_FILE(silc_pkcs_pgp_import_public_key_file)
37 {
38   SilcList list;
39   SilcBool ret;
40   unsigned char *data = NULL;
41   SilcPGPPublicKey pubkey;
42
43   SILC_LOG_DEBUG(("Parsing OpenPGP public key file"));
44
45   if (!ret_public_key)
46     return FALSE;
47
48   switch (encoding) {
49   case SILC_PKCS_FILE_BIN:
50     break;
51
52   case SILC_PKCS_FILE_BASE64:
53     data = silc_pgp_dearmor(filedata, filedata_len, &filedata_len);
54     if (!data)
55       return FALSE;
56     filedata = data;
57     break;
58   }
59
60   /* Parse PGP packets */
61   if (!silc_pgp_packet_decode(filedata, filedata_len, NULL, &list)) {
62     silc_free(data);
63     return FALSE;
64   }
65   silc_free(data);
66
67   /* Parse the public key */
68   ret = silc_pgp_public_key_decode(&list, &pubkey);
69   if (ret) {
70     if (ret_alg)
71       *ret_alg = pubkey->pkcs;
72     if (ret_public_key)
73       *ret_public_key = pubkey;
74   }
75
76   silc_pgp_packet_free_list(&list);
77
78   return ret;
79 }
80
81 /* Import OpenPGP public key packet (OpenPGP certificate). */
82
83 SILC_PKCS_IMPORT_PUBLIC_KEY(silc_pkcs_pgp_import_public_key)
84 {
85   SilcPGPPublicKey pubkey;
86   int ret;
87
88   pubkey = silc_calloc(1, sizeof(*pubkey));
89   if (!pubkey)
90     return 0;
91
92   ret = silc_pgp_packet_public_key_decode(key, key_len, pubkey);
93   if (ret) {
94     if (ret_alg)
95       *ret_alg = pubkey->pkcs;
96     if (ret_public_key)
97       *ret_public_key = pubkey;
98   } else {
99     silc_free(pubkey);
100   }
101
102   return ret;
103 }
104
105 /* Export PGP public key file */
106
107 SILC_PKCS_EXPORT_PUBLIC_KEY_FILE(silc_pkcs_pgp_export_public_key_file)
108 {
109   return 0;
110 }
111
112 /* Export OpenPGP public key */
113
114 SILC_PKCS_EXPORT_PUBLIC_KEY(silc_pkcs_pgp_export_public_key)
115 {
116   return 0;
117 }
118
119 /* Return public key length in bits */
120
121 SILC_PKCS_PUBLIC_KEY_BITLEN(silc_pkcs_pgp_public_key_bitlen)
122
123 {
124   SilcPGPPublicKey pubkey = public_key;
125   return pubkey->pkcs->public_key_bitlen(pubkey->pkcs, pubkey->public_key);
126 }
127
128 /* Copy public key */
129
130 SILC_PKCS_PUBLIC_KEY_COPY(silc_pkcs_pgp_public_key_copy)
131 {
132   SilcPGPPublicKey pubkey = public_key, new_pubkey, p;
133   SilcPGPPacket packet;
134
135   new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
136   if (!new_pubkey)
137     return NULL;
138
139   if (pubkey->subkeys) {
140     new_pubkey->subkeys = silc_dlist_init();
141     if (!new_pubkey->subkeys) {
142       silc_free(new_pubkey);
143       return NULL;
144     }
145
146     silc_dlist_start(pubkey->subkeys);
147     while ((p = silc_dlist_get(pubkey->subkeys))) {
148       p = silc_pkcs_pgp_public_key_copy(pkcs, p);
149       if (p)
150         silc_dlist_add(new_pubkey->subkeys, p);
151     }
152   }
153
154   silc_list_init(new_pubkey->packets, struct SilcPGPPacketStruct, next);
155   silc_list_start(pubkey->packets);
156   while ((packet = silc_list_get(pubkey->packets))) {
157     packet = silc_pgp_packet_copy(packet);
158     if (packet) {
159       silc_free(new_pubkey);
160       return NULL;
161     }
162     silc_list_add(new_pubkey->packets, packet);
163   }
164
165   memcpy(new_pubkey->key_id, pubkey->key_id, sizeof(pubkey->key_id));
166   memcpy(new_pubkey->fingerprint, pubkey->fingerprint,
167          sizeof(pubkey->fingerprint));
168   new_pubkey->created = pubkey->created;
169   new_pubkey->valid = pubkey->valid;
170   new_pubkey->version = pubkey->version;
171   new_pubkey->algorithm = pubkey->algorithm;
172
173   new_pubkey->public_key = pubkey->pkcs->public_key_copy(pubkey->pkcs,
174                                                          pubkey->public_key);
175   if (!new_pubkey->public_key) {
176     silc_free(new_pubkey);
177     return NULL;
178   }
179
180   return new_pubkey;
181 }
182
183 /* Compares public keys */
184
185 SILC_PKCS_PUBLIC_KEY_COMPARE(silc_pkcs_pgp_public_key_compare)
186 {
187   SilcPGPPublicKey k1 = key1, k2 = key2;
188
189   if (k1->version != k2->version)
190     return FALSE;
191   if (k1->created != k2->created)
192     return FALSE;
193   if (k1->valid != k2->valid)
194     return FALSE;
195   if (k1->algorithm != k2->algorithm)
196     return FALSE;
197   if (memcmp(k1->key_id, k2->key_id, sizeof(k1->key_id)))
198     return FALSE;
199   if (memcmp(k1->fingerprint, k2->fingerprint, sizeof(k1->fingerprint)))
200     return FALSE;
201
202   return k1->pkcs->public_key_compare(k1->pkcs,
203                                       k1->public_key, k2->public_key);
204 }
205
206 /* Free public key */
207
208 SILC_PKCS_PUBLIC_KEY_FREE(silc_pkcs_pgp_public_key_free)
209 {
210   silc_pgp_public_key_free(public_key);
211 }
212
213 /* Import PGP private key file */
214
215 SILC_PKCS_IMPORT_PRIVATE_KEY_FILE(silc_pkcs_pgp_import_private_key_file)
216 {
217   SilcList list;
218   SilcBool ret;
219   unsigned char *data = NULL;
220   SilcPGPPrivateKey privkey;
221
222   SILC_LOG_DEBUG(("Parsing OpenPGP private key file"));
223
224   if (!ret_private_key)
225     return FALSE;
226
227   switch (encoding) {
228   case SILC_PKCS_FILE_BIN:
229     break;
230
231   case SILC_PKCS_FILE_BASE64:
232     data = silc_pgp_dearmor(filedata, filedata_len, &filedata_len);
233     if (!data)
234       return FALSE;
235     filedata = data;
236     break;
237   }
238
239   /* Parse PGP packets */
240   if (!silc_pgp_packet_decode(filedata, filedata_len, NULL, &list)) {
241     silc_free(data);
242     return FALSE;
243   }
244   silc_free(data);
245
246   /* Parse the private key */
247   ret = silc_pgp_private_key_decode(&list, passphrase, passphrase_len,
248                                     &privkey);
249   if (ret) {
250     if (ret_alg)
251       *ret_alg = privkey->public_key->pkcs;
252     if (ret_private_key)
253       *ret_private_key = privkey;
254   }
255
256   silc_pgp_packet_free_list(&list);
257
258   return ret;
259 }
260
261 /* Import OpenPGP private key */
262
263 SILC_PKCS_IMPORT_PRIVATE_KEY(silc_pkcs_pgp_import_private_key)
264 {
265   SilcPGPPrivateKey privkey;
266   int ret;
267
268   privkey = silc_calloc(1, sizeof(*privkey));
269   if (!privkey)
270     return 0;
271
272   ret = silc_pgp_packet_private_key_decode(key, key_len, passphrase,
273                                            passphrase_len, privkey);
274   if (ret) {
275     if (ret_alg)
276       *ret_alg = privkey->public_key->pkcs;
277     if (ret_private_key)
278       *ret_private_key = privkey;
279   } else {
280     silc_free(privkey);
281   }
282
283   return ret;
284 }
285
286 /* Export PGP private key file */
287
288 SILC_PKCS_EXPORT_PRIVATE_KEY_FILE(silc_pkcs_pgp_export_private_key_file)
289 {
290   return 0;
291 }
292
293 /* Export OpenPGP private key */
294
295 SILC_PKCS_EXPORT_PRIVATE_KEY(silc_pkcs_pgp_export_private_key)
296 {
297   return 0;
298 }
299
300 /* Returns key length in bits */
301
302 SILC_PKCS_PRIVATE_KEY_BITLEN(silc_pkcs_pgp_private_key_bitlen)
303 {
304   SilcPGPPrivateKey privkey = private_key;
305   return silc_pkcs_pgp_public_key_bitlen(pkcs, privkey->public_key);
306 }
307
308 /* Free private key */
309
310 SILC_PKCS_PRIVATE_KEY_FREE(silc_pkcs_pgp_private_key_free)
311 {
312   SilcPGPPrivateKey privkey = private_key;
313   silc_pgp_private_key_free(privkey);
314 }
315
316 /* Encrypt */
317
318 SILC_PKCS_ENCRYPT(silc_pkcs_pgp_encrypt)
319 {
320   return 0;
321 }
322
323 /* Decrypt */
324
325 SILC_PKCS_DECRYPT(silc_pkcs_pgp_decrypt)
326 {
327   return 0;
328 }
329
330 /* Sign */
331
332 SILC_PKCS_SIGN(silc_pkcs_pgp_sign)
333 {
334   return 0;
335 }
336
337 /* Verify */
338
339 SILC_PKCS_VERIFY(silc_pkcs_pgp_verify)
340 {
341   return 0;
342 }
343
344 /************************** OpenPGP RSA PKCS API ****************************/
345
346 /* Import OpenPGP compliant RSA public key */
347
348 SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_pgp_rsa_import_public_key)
349 {
350   SilcBufferStruct alg_key;
351   RsaPublicKey *pubkey;
352   unsigned char *n, *e;
353   SilcUInt16 n_len, e_len;
354
355   if (!ret_public_key)
356     return 0;
357
358   /* Allocate RSA public key */
359   *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey));
360   if (!pubkey)
361     return FALSE;
362
363   /* Parse OpenPGP RSA public key */
364   silc_buffer_set(&alg_key, key, key_len);
365   if (silc_buffer_unformat(&alg_key,
366                            SILC_STR_ADVANCE,
367                            SILC_STR_UINT16(&n_len),
368                            SILC_STR_END) < 0)
369     goto err;
370
371   n_len = (n_len + 7) / 8;
372   if (!n_len)
373     goto err;
374
375   if (silc_buffer_unformat(&alg_key,
376                            SILC_STR_ADVANCE,
377                            SILC_STR_DATA(&n, n_len),
378                            SILC_STR_UINT16(&e_len),
379                            SILC_STR_END) < 0)
380     goto err;
381
382   e_len = (e_len + 7) / 8;
383   if (!e_len)
384     goto err;
385
386   if (silc_buffer_unformat(&alg_key,
387                            SILC_STR_ADVANCE,
388                            SILC_STR_DATA(&e, e_len),
389                            SILC_STR_END) < 0)
390     goto err;
391
392   /* Get MP integers */
393   silc_mp_init(&pubkey->n);
394   silc_mp_init(&pubkey->e);
395   silc_mp_bin2mp(n, n_len, &pubkey->n);
396   silc_mp_bin2mp(e, e_len, &pubkey->e);
397
398   /* Set key length */
399   pubkey->bits = silc_mp_sizeinbase(&pubkey->n, 2);
400
401   return silc_buffer_headlen(&alg_key);
402
403  err:
404   silc_free(pubkey);
405   return 0;
406 }
407
408 /* Export OpenPGP compliant RSA public key */
409
410 SILC_PKCS_ALG_EXPORT_PUBLIC_KEY(silc_pgp_rsa_export_public_key)
411 {
412   RsaPublicKey *pubkey = public_key;
413   SilcBufferStruct alg_key;
414   unsigned char *n = NULL, *e = NULL, *ret;
415   SilcUInt16 n_len, e_len;
416
417   n_len = silc_mp_sizeinbase(&pubkey->n, 2);
418   e_len = silc_mp_sizeinbase(&pubkey->e, 2);
419
420   /* Encode MP integers */
421   n = silc_mp_mp2bin(&pubkey->n, 0, NULL);
422   if (!n)
423     goto err;
424   e = silc_mp_mp2bin(&pubkey->e, 0, NULL);
425   if (!e)
426     goto err;
427
428   memset(&alg_key, 0, sizeof(alg_key));
429   if (silc_buffer_format(&alg_key,
430                          SILC_STR_UINT16(n_len),
431                          SILC_STR_DATA(n, n_len),
432                          SILC_STR_UINT16(e_len),
433                          SILC_STR_DATA(e, e_len),
434                          SILC_STR_END) < 0)
435     goto err;
436
437   silc_free(n);
438   silc_free(e);
439
440   ret = silc_buffer_steal(&alg_key, ret_len);
441   return ret;
442
443  err:
444   silc_free(n);
445   silc_free(e);
446   return NULL;
447 }
448
449 /* Import OpenPGP compliant RSA private key */
450
451 SILC_PKCS_ALG_IMPORT_PRIVATE_KEY(silc_pgp_rsa_import_private_key)
452 {
453   SilcBufferStruct alg_key;
454   RsaPrivateKey *privkey;
455   unsigned char *d, *p, *q, *u;
456   SilcUInt16 d_len, p_len, q_len, u_len;
457   SilcMPInt pm1, qm1;
458
459   if (!ret_private_key)
460     return 0;
461
462   /* Allocate RSA private key */
463   *ret_private_key = privkey = silc_calloc(1, sizeof(*privkey));
464   if (!privkey)
465     goto err;
466
467   /* Parse OpenPGP RSA private key.  In OpenPGP the u is p^-1 mod q, but
468      our RSA implementation expects q^-1 mod p (PKCS#1 compliant), thus
469      we reverse p and q to make it work. */
470   silc_buffer_set(&alg_key, key, key_len);
471   if (silc_buffer_unformat(&alg_key,
472                            SILC_STR_ADVANCE,
473                            SILC_STR_UINT16(&d_len),
474                            SILC_STR_END) < 0)
475     goto err;
476
477   d_len = (d_len + 7) / 8;
478   if (!d_len)
479     goto err;
480
481   if (silc_buffer_unformat(&alg_key,
482                            SILC_STR_ADVANCE,
483                            SILC_STR_DATA(&d, d_len),
484                            SILC_STR_UINT16(&q_len),
485                            SILC_STR_END) < 0)
486     goto err;
487
488   q_len = (q_len + 7) / 8;
489   if (!q_len)
490     goto err;
491
492   if (silc_buffer_unformat(&alg_key,
493                            SILC_STR_ADVANCE,
494                            SILC_STR_DATA(&q, q_len),
495                            SILC_STR_UINT16(&p_len),
496                            SILC_STR_END) < 0)
497     goto err;
498
499   p_len = (p_len + 7) / 8;
500   if (!p_len)
501     goto err;
502
503   if (silc_buffer_unformat(&alg_key,
504                            SILC_STR_ADVANCE,
505                            SILC_STR_DATA(&p, p_len),
506                            SILC_STR_UINT16(&u_len),
507                            SILC_STR_END) < 0)
508     goto err;
509
510   u_len = (u_len + 7) / 8;
511   if (!u_len)
512     goto err;
513
514   if (silc_buffer_unformat(&alg_key,
515                            SILC_STR_ADVANCE,
516                            SILC_STR_DATA(&u, u_len),
517                            SILC_STR_END) < 0)
518     goto err;
519
520   /* Get MP integers */
521   silc_mp_init(&privkey->d);
522   silc_mp_init(&privkey->p);
523   silc_mp_init(&privkey->q);
524   silc_mp_init(&privkey->qP);
525   silc_mp_bin2mp(d, d_len, &privkey->d);
526   silc_mp_bin2mp(p, p_len, &privkey->p);
527   silc_mp_bin2mp(q, q_len, &privkey->q);
528   silc_mp_bin2mp(u, u_len, &privkey->qP);
529
530   /* Fill in missing integers and pre-compute */
531   silc_mp_init(&pm1);
532   silc_mp_init(&qm1);
533   silc_mp_init(&privkey->n);
534   silc_mp_init(&privkey->e);
535   silc_mp_init(&privkey->dP);
536   silc_mp_init(&privkey->dQ);
537   silc_mp_mul(&privkey->n, &privkey->p, &privkey->q);
538   silc_mp_sub_ui(&pm1, &privkey->p, 1);
539   silc_mp_sub_ui(&qm1, &privkey->q, 1);
540   silc_mp_mod(&privkey->dP, &privkey->d, &pm1);
541   silc_mp_mod(&privkey->dQ, &privkey->d, &qm1);
542   silc_mp_uninit(&pm1);
543   silc_mp_uninit(&qm1);
544
545   /* Set key length */
546   privkey->bits = silc_mp_sizeinbase(&privkey->n, 2);
547
548   return silc_buffer_headlen(&alg_key);
549
550  err:
551   silc_free(privkey);
552   return 0;
553 }
554
555 /* Export OpenPGP compliant RSA private key */
556
557 SILC_PKCS_ALG_EXPORT_PRIVATE_KEY(silc_pgp_rsa_export_private_key)
558 {
559   RsaPrivateKey *privkey = private_key;
560   SilcBufferStruct alg_key;
561   unsigned char *d = NULL, *p = NULL, *q = NULL, *u = NULL, *ret;
562   SilcUInt16 d_len, p_len, q_len, u_len;
563
564   /* In OpenPGP the u is p^-1 mod q, but our RSA implementation uses
565      q^-1 mod p (PKCS#1 compliant), thus we reverse p and q to make the
566      key correct. */
567   d_len = silc_mp_sizeinbase(&privkey->d, 2);
568   p_len = silc_mp_sizeinbase(&privkey->q, 2);
569   q_len = silc_mp_sizeinbase(&privkey->p, 2);
570   u_len = silc_mp_sizeinbase(&privkey->qP, 2);
571
572   /* Encode MP integers */
573   d = silc_mp_mp2bin(&privkey->d, 0, NULL);
574   if (!d)
575     goto err;
576   p = silc_mp_mp2bin(&privkey->q, 0, NULL);
577   if (!p)
578     goto err;
579   q = silc_mp_mp2bin(&privkey->p, 0, NULL);
580   if (!q)
581     goto err;
582   u = silc_mp_mp2bin(&privkey->qP, 0, NULL);
583   if (!u)
584     goto err;
585
586   memset(&alg_key, 0, sizeof(alg_key));
587   if (silc_buffer_format(&alg_key,
588                          SILC_STR_UINT16(d_len),
589                          SILC_STR_DATA(d, d_len),
590                          SILC_STR_UINT16(p_len),
591                          SILC_STR_DATA(p, p_len),
592                          SILC_STR_UINT16(q_len),
593                          SILC_STR_DATA(q, q_len),
594                          SILC_STR_UINT16(u_len),
595                          SILC_STR_DATA(u, u_len),
596                          SILC_STR_END) < 0)
597     goto err;
598
599   silc_free(d);
600   silc_free(p);
601   silc_free(q);
602   silc_free(u);
603
604   ret = silc_buffer_steal(&alg_key, ret_len);
605   return ret;
606
607  err:
608   silc_free(d);
609   silc_free(p);
610   silc_free(q);
611   silc_free(u);
612   return NULL;
613 }
614
615 /************************** OpenPGP DSA PKCS API ****************************/
616
617 /* Import OpenPGP compliant DSA public key */
618
619 SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_pgp_dsa_import_public_key)
620 {
621   SilcBufferStruct alg_key;
622   DsaPublicKey *pubkey;
623   unsigned char *p, *q, *g, *y;
624   SilcUInt16 p_len, q_len, g_len, y_len;
625
626   if (!ret_public_key)
627     return 0;
628
629   /* Allocate DSA public key */
630   *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey));
631   if (!pubkey)
632     return FALSE;
633
634   /* Parse OpenPGP DSA public key */
635   silc_buffer_set(&alg_key, key, key_len);
636   if (silc_buffer_unformat(&alg_key,
637                            SILC_STR_ADVANCE,
638                            SILC_STR_UINT16(&p_len),
639                            SILC_STR_END) < 0)
640     goto err;
641
642   p_len = (p_len + 7) / 8;
643   if (!p_len)
644     goto err;
645
646   if (silc_buffer_unformat(&alg_key,
647                            SILC_STR_ADVANCE,
648                            SILC_STR_DATA(&p, p_len),
649                            SILC_STR_UINT16(&q_len),
650                            SILC_STR_END) < 0)
651     goto err;
652
653   q_len = (q_len + 7) / 8;
654   if (!q_len)
655     goto err;
656
657   if (silc_buffer_unformat(&alg_key,
658                            SILC_STR_ADVANCE,
659                            SILC_STR_DATA(&q, q_len),
660                            SILC_STR_UINT16(&g_len),
661                            SILC_STR_END) < 0)
662     goto err;
663
664   g_len = (g_len + 7) / 8;
665   if (!g_len)
666     goto err;
667
668   if (silc_buffer_unformat(&alg_key,
669                            SILC_STR_ADVANCE,
670                            SILC_STR_DATA(&g, g_len),
671                            SILC_STR_UINT16(&y_len),
672                            SILC_STR_END) < 0)
673     goto err;
674
675   y_len = (y_len + 7) / 8;
676   if (!y_len)
677     goto err;
678
679   if (silc_buffer_unformat(&alg_key,
680                            SILC_STR_ADVANCE,
681                            SILC_STR_DATA(&y, y_len),
682                            SILC_STR_END) < 0)
683     goto err;
684
685   /* Get MP integers */
686   silc_mp_init(&pubkey->p);
687   silc_mp_init(&pubkey->q);
688   silc_mp_init(&pubkey->g);
689   silc_mp_init(&pubkey->y);
690   silc_mp_bin2mp(p, p_len, &pubkey->p);
691   silc_mp_bin2mp(q, q_len, &pubkey->q);
692   silc_mp_bin2mp(g, g_len, &pubkey->g);
693   silc_mp_bin2mp(y, y_len, &pubkey->y);
694
695   /* Set key length */
696   pubkey->bits = silc_mp_sizeinbase(&pubkey->p, 2);
697
698   return silc_buffer_headlen(&alg_key);
699
700  err:
701   silc_free(pubkey);
702   return 0;
703 }
704
705 /* Export OpenPGP compliant DSA public key */
706
707 SILC_PKCS_ALG_EXPORT_PUBLIC_KEY(silc_pgp_dsa_export_public_key)
708 {
709   return 0;
710 }
711
712 /* Import OpenPGP compliant DSA private key */
713
714 SILC_PKCS_ALG_IMPORT_PRIVATE_KEY(silc_pgp_dsa_import_private_key)
715 {
716   SilcBufferStruct alg_key;
717   DsaPrivateKey *privkey;
718   unsigned char *x;
719   SilcUInt16 x_len;
720
721   if (!ret_private_key)
722     return 0;
723
724   /* Allocate DSA private key */
725   *ret_private_key = privkey = silc_calloc(1, sizeof(*privkey));
726   if (!privkey)
727     goto err;
728
729   /* Parse OpenPGP DSA private key. */
730   silc_buffer_set(&alg_key, key, key_len);
731   if (silc_buffer_unformat(&alg_key,
732                            SILC_STR_ADVANCE,
733                            SILC_STR_UINT16(&x_len),
734                            SILC_STR_END) < 0)
735     goto err;
736
737   x_len = (x_len + 7) / 8;
738   if (!x_len)
739     goto err;
740
741   if (silc_buffer_unformat(&alg_key,
742                            SILC_STR_ADVANCE,
743                            SILC_STR_DATA(&x, x_len),
744                            SILC_STR_END) < 0)
745     goto err;
746
747   /* Get MP integers */
748   silc_mp_init(&privkey->x);
749   silc_mp_bin2mp(x, x_len, &privkey->x);
750
751   return silc_buffer_headlen(&alg_key);
752
753  err:
754   silc_free(privkey);
755   return 0;
756 }
757
758 /* Export OpenPGP compliant DSA private key */
759
760 SILC_PKCS_ALG_EXPORT_PRIVATE_KEY(silc_pgp_dsa_export_private_key)
761 {
762   return 0;
763 }