1 /* protect.c - Un/Protect a secret key
2 * Copyright (C) 1998, 1999, 2000, 2001, 2002,
3 * 2003 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
34 #include "sexp-parse.h"
36 #define PROT_CIPHER GCRY_CIPHER_AES
37 #define PROT_CIPHER_STRING "aes"
38 #define PROT_CIPHER_KEYLEN (128/8)
41 /* A table containing the information needed to create a protected
46 int prot_from
, prot_to
;
48 { "rsa", "nedpqu", 2, 5 },
49 { "dsa", "pqgyx", 4, 4 },
50 { "elg", "pgyx", 3, 3 },
56 hash_passphrase (const char *passphrase
, int hashalgo
,
58 const unsigned char *s2ksalt
, unsigned long s2kcount
,
59 unsigned char *key
, size_t keylen
);
63 /* Calculate the MIC for a private key S-Exp. SHA1HASH should point to
64 a 20 byte buffer. This function is suitable for any algorithms. */
66 calculate_mic (const unsigned char *plainkey
, unsigned char *sha1hash
)
68 const unsigned char *hash_begin
, *hash_end
;
69 const unsigned char *s
;
74 return gpg_error (GPG_ERR_INV_SEXP
);
78 return gpg_error (GPG_ERR_INV_SEXP
);
79 if (!smatch (&s
, n
, "private-key"))
80 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
82 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
87 return gpg_error (GPG_ERR_INV_SEXP
);
88 s
+= n
; /* skip over the algorithm name */
95 return gpg_error (GPG_ERR_INV_SEXP
);
99 return gpg_error (GPG_ERR_INV_SEXP
);
102 return gpg_error (GPG_ERR_INV_SEXP
);
106 return gpg_error (GPG_ERR_INV_SEXP
);
110 gcry_md_hash_buffer (GCRY_MD_SHA1
, sha1hash
,
111 hash_begin
, hash_end
- hash_begin
);
118 /* Encrypt the parameter block starting at PROTBEGIN with length
119 PROTLEN using the utf8 encoded key PASSPHRASE and return the entire
120 encrypted block in RESULT or return with an error code. SHA1HASH
121 is the 20 byte SHA-1 hash required for the integrity code.
123 The parameter block is expected to be an incomplete S-Expression of
124 the form (example in advanced format):
126 (d #046129F..[some bytes not shown]..81#)
127 (p #00e861b..[some bytes not shown]..f1#)
128 (q #00f7a7c..[some bytes not shown]..61#)
129 (u #304559a..[some bytes not shown]..9b#)
131 the returned block is the S-Expression:
133 (protected mode (parms) encrypted_octet_string)
137 do_encryption (const unsigned char *protbegin
, size_t protlen
,
138 const char *passphrase
, const unsigned char *sha1hash
,
139 unsigned char **result
, size_t *resultlen
)
142 const char *modestr
= "openpgp-s2k3-sha1-" PROT_CIPHER_STRING
"-cbc";
143 int blklen
, enclen
, outlen
;
144 unsigned char *iv
= NULL
;
148 int saltpos
, ivpos
, encpos
;
153 rc
= gcry_cipher_open (&hd
, PROT_CIPHER
, GCRY_CIPHER_MODE_CBC
,
159 /* We need to work on a copy of the data because this makes it
160 easier to add the trailer and the padding and more important we
161 have to prefix the text with 2 parenthesis, so we have to
162 allocate enough space for:
164 ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
166 We always append a full block of random bytes as padding but
167 encrypt only what is needed for a full blocksize */
168 blklen
= gcry_cipher_get_algo_blklen (PROT_CIPHER
);
169 outlen
= 2 + protlen
+ 2 + 6 + 6 + 23 + 2 + blklen
;
170 enclen
= outlen
/blklen
* blklen
;
171 outbuf
= gcry_malloc_secure (outlen
);
176 /* Allocate random bytes to be used as IV, padding and s2k salt. */
177 iv
= xtrymalloc (blklen
*2+8);
179 rc
= gpg_error (GPG_ERR_ENOMEM
);
180 gcry_create_nonce (iv
, blklen
*2+8);
181 rc
= gcry_cipher_setiv (hd
, iv
, blklen
);
186 size_t keylen
= PROT_CIPHER_KEYLEN
;
188 key
= gcry_malloc_secure (keylen
);
193 rc
= hash_passphrase (passphrase
, GCRY_MD_SHA1
,
194 3, iv
+2*blklen
, 96, key
, keylen
);
196 rc
= gcry_cipher_setkey (hd
, key
, keylen
);
205 memcpy (p
, protbegin
, protlen
);
207 memcpy (p
, ")(4:hash4:sha120:", 17);
209 memcpy (p
, sha1hash
, 20);
213 memcpy (p
, iv
+blklen
, blklen
);
215 assert ( p
- outbuf
== outlen
);
216 rc
= gcry_cipher_encrypt (hd
, outbuf
, enclen
, NULL
, 0);
218 gcry_cipher_close (hd
);
226 /* Now allocate the buffer we want to return. This is
228 (protected openpgp-s2k3-sha1-aes-cbc
229 ((sha1 salt no_of_iterations) 16byte_iv)
230 encrypted_octet_string)
232 in canoncical format of course. We use asprintf and %n modifier
233 and spaces as palceholders. */
235 "(9:protected%d:%s((4:sha18:%n_8bytes_2:96)%d:%n%*s)%d:%n%*s)",
236 (int)strlen (modestr
), modestr
,
238 blklen
, &ivpos
, blklen
, "",
239 enclen
, &encpos
, enclen
, "");
241 { /* asprintf does not use our malloc system */
243 p
= xtrymalloc (strlen (psave
)+1);
250 gpg_error_t tmperr
= out_of_core ();
255 *resultlen
= strlen (p
);
256 *result
= (unsigned char*)p
;
257 memcpy (p
+saltpos
, iv
+2*blklen
, 8);
258 memcpy (p
+ivpos
, iv
, blklen
);
259 memcpy (p
+encpos
, outbuf
, enclen
);
267 /* Protect the key encoded in canonical format in PLAINKEY. We assume
268 a valid S-Exp here. */
270 agent_protect (const unsigned char *plainkey
, const char *passphrase
,
271 unsigned char **result
, size_t *resultlen
)
274 const unsigned char *s
;
275 const unsigned char *hash_begin
, *hash_end
;
276 const unsigned char *prot_begin
, *prot_end
, *real_end
;
279 unsigned char hashvalue
[20];
280 unsigned char *protected;
287 return gpg_error (GPG_ERR_INV_SEXP
);
292 return gpg_error (GPG_ERR_INV_SEXP
);
293 if (!smatch (&s
, n
, "private-key"))
294 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
296 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
302 return gpg_error (GPG_ERR_INV_SEXP
);
304 for (infidx
=0; protect_info
[infidx
].algo
305 && !smatch (&s
, n
, protect_info
[infidx
].algo
); infidx
++)
307 if (!protect_info
[infidx
].algo
)
308 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM
);
310 prot_begin
= prot_end
= NULL
;
311 for (i
=0; (c
=protect_info
[infidx
].parmlist
[i
]); i
++)
313 if (i
== protect_info
[infidx
].prot_from
)
316 return gpg_error (GPG_ERR_INV_SEXP
);
321 return gpg_error (GPG_ERR_INV_SEXP
);
322 if (n
!= 1 || c
!= *s
)
323 return gpg_error (GPG_ERR_INV_SEXP
);
327 return gpg_error (GPG_ERR_INV_SEXP
);
328 s
+=n
; /* skip value */
330 return gpg_error (GPG_ERR_INV_SEXP
);
332 if (i
== protect_info
[infidx
].prot_to
)
336 if (*s
!= ')' || !prot_begin
|| !prot_end
)
337 return gpg_error (GPG_ERR_INV_SEXP
);
341 /* skip to the end of the S-exp */
343 rc
= sskip (&s
, &depth
);
349 gcry_md_hash_buffer (GCRY_MD_SHA1
, hashvalue
,
350 hash_begin
, hash_end
- hash_begin
+ 1);
352 rc
= do_encryption (prot_begin
, prot_end
- prot_begin
+ 1,
353 passphrase
, hashvalue
,
354 &protected, &protectedlen
);
358 /* Now create the protected version of the key. Note that the 10
359 extra bytes are for for the inserted "protected-" string (the
360 beginning of the plaintext reads: "((11:private-key(" ). */
362 + (prot_begin
-plainkey
)
364 + (real_end
-prot_end
));
365 *result
= p
= xtrymalloc (*resultlen
);
368 gpg_error_t tmperr
= out_of_core ();
372 memcpy (p
, "(21:protected-", 14);
374 memcpy (p
, plainkey
+4, prot_begin
- plainkey
- 4);
375 p
+= prot_begin
- plainkey
- 4;
376 memcpy (p
, protected, protectedlen
);
378 memcpy (p
, prot_end
+1, real_end
- prot_end
);
379 p
+= real_end
- prot_end
;
380 assert ( p
- *result
== *resultlen
);
386 /* Do the actual decryption and check the return list for consistency. */
388 do_decryption (const unsigned char *protected, size_t protectedlen
,
389 const char *passphrase
,
390 const unsigned char *s2ksalt
, unsigned long s2kcount
,
391 const unsigned char *iv
, size_t ivlen
,
392 unsigned char **result
)
397 unsigned char *outbuf
;
400 blklen
= gcry_cipher_get_algo_blklen (PROT_CIPHER
);
401 if (protectedlen
< 4 || (protectedlen
%blklen
))
402 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
404 rc
= gcry_cipher_open (&hd
, PROT_CIPHER
, GCRY_CIPHER_MODE_CBC
,
409 outbuf
= gcry_malloc_secure (protectedlen
);
413 rc
= gcry_cipher_setiv (hd
, iv
, ivlen
);
417 size_t keylen
= PROT_CIPHER_KEYLEN
;
419 key
= gcry_malloc_secure (keylen
);
424 rc
= hash_passphrase (passphrase
, GCRY_MD_SHA1
,
425 3, s2ksalt
, s2kcount
, key
, keylen
);
427 rc
= gcry_cipher_setkey (hd
, key
, keylen
);
432 rc
= gcry_cipher_decrypt (hd
, outbuf
, protectedlen
,
433 protected, protectedlen
);
434 gcry_cipher_close (hd
);
440 /* Do a quick check first. */
441 if (*outbuf
!= '(' && outbuf
[1] != '(')
444 return gpg_error (GPG_ERR_BAD_PASSPHRASE
);
446 /* Check that we have a consistent S-Exp. */
447 reallen
= gcry_sexp_canon_len (outbuf
, protectedlen
, NULL
, NULL
);
448 if (!reallen
|| (reallen
+ blklen
< protectedlen
) )
451 return gpg_error (GPG_ERR_BAD_PASSPHRASE
);
458 /* Merge the parameter list contained in CLEARTEXT with the original
459 protect lists PROTECTEDKEY by replacing the list at REPLACEPOS.
460 Return the new list in RESULT and the MIC value in the 20 byte
463 merge_lists (const unsigned char *protectedkey
,
465 const unsigned char *cleartext
,
466 unsigned char *sha1hash
,
467 unsigned char **result
, size_t *resultlen
)
469 size_t n
, newlistlen
;
470 unsigned char *newlist
, *p
;
471 const unsigned char *s
;
472 const unsigned char *startpos
, *endpos
;
479 return gpg_error (GPG_ERR_BUG
);
481 /* Estimate the required size of the resulting list. We have a large
482 safety margin of >20 bytes (MIC hash from CLEARTEXT and the
483 removed "protected-" */
484 newlistlen
= gcry_sexp_canon_len (protectedkey
, 0, NULL
, NULL
);
486 return gpg_error (GPG_ERR_BUG
);
487 n
= gcry_sexp_canon_len (cleartext
, 0, NULL
, NULL
);
489 return gpg_error (GPG_ERR_BUG
);
491 newlist
= gcry_malloc_secure (newlistlen
);
493 return out_of_core ();
495 /* Copy the initial segment */
496 strcpy ((char*)newlist
, "(11:private-key");
498 memcpy (p
, protectedkey
+15+10, replacepos
-15-10);
499 p
+= replacepos
-15-10;
501 /* copy the cleartext */
503 if (*s
!= '(' && s
[1] != '(')
504 return gpg_error (GPG_ERR_BUG
); /*we already checked this */
526 /* short intermezzo: Get the MIC */
531 if (!smatch (&s
, n
, "hash"))
534 if (!smatch (&s
, n
, "sha1"))
539 memcpy (sha1hash
, s
, 20);
545 /* append the parameter list */
546 memcpy (p
, startpos
, endpos
- startpos
);
547 p
+= endpos
- startpos
;
549 /* skip overt the protected list element in the original list */
550 s
= protectedkey
+ replacepos
;
558 i
= 2; /* we are inside this level */
562 assert (s
[-1] == ')');
563 endpos
= s
; /* one behind the end of the list */
565 /* append the rest */
566 memcpy (p
, startpos
, endpos
- startpos
);
567 p
+= endpos
- startpos
;
571 *resultlen
= newlistlen
;
575 wipememory (newlist
, newlistlen
);
580 wipememory (newlist
, newlistlen
);
582 return gpg_error (GPG_ERR_INV_SEXP
);
587 /* Unprotect the key encoded in canonical format. We assume a valid
590 agent_unprotect (const unsigned char *protectedkey
, const char *passphrase
,
591 unsigned char **result
, size_t *resultlen
)
594 const unsigned char *s
;
597 unsigned char sha1hash
[20], sha1hash2
[20];
598 const unsigned char *s2ksalt
;
599 unsigned long s2kcount
;
600 const unsigned char *iv
;
601 const unsigned char *prot_begin
;
602 unsigned char *cleartext
;
603 unsigned char *final
;
608 return gpg_error (GPG_ERR_INV_SEXP
);
612 return gpg_error (GPG_ERR_INV_SEXP
);
613 if (!smatch (&s
, n
, "protected-private-key"))
614 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
616 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
620 return gpg_error (GPG_ERR_INV_SEXP
);
622 for (infidx
=0; protect_info
[infidx
].algo
623 && !smatch (&s
, n
, protect_info
[infidx
].algo
); infidx
++)
625 if (!protect_info
[infidx
].algo
)
626 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM
);
628 /* Now find the list with the protected information. Here is an
629 example for such a list:
630 (protected openpgp-s2k3-sha1-aes-cbc
631 ((sha1 <salt> <count>) <Initialization_Vector>)
637 return gpg_error (GPG_ERR_INV_SEXP
);
642 return gpg_error (GPG_ERR_INV_SEXP
);
643 if (smatch (&s
, n
, "protected"))
654 return gpg_error (GPG_ERR_INV_SEXP
);
655 if (!smatch (&s
, n
, "openpgp-s2k3-sha1-" PROT_CIPHER_STRING
"-cbc"))
656 return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION
);
657 if (*s
!= '(' || s
[1] != '(')
658 return gpg_error (GPG_ERR_INV_SEXP
);
662 return gpg_error (GPG_ERR_INV_SEXP
);
663 if (!smatch (&s
, n
, "sha1"))
664 return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION
);
667 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
672 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
673 /* We expect a list close as next, so we can simply use strtoul()
674 here. We might want to check that we only have digits - but this
675 is nothing we should worry about */
677 return gpg_error (GPG_ERR_INV_SEXP
);
678 s2kcount
= strtoul ((const char*)s
, NULL
, 10);
680 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
682 s
++; /* skip list end */
685 if (n
!= 16) /* Wrong blocksize for IV (we support only aes-128). */
686 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
690 return gpg_error (GPG_ERR_INV_SEXP
);
694 return gpg_error (GPG_ERR_INV_SEXP
);
696 rc
= do_decryption (s
, n
,
697 passphrase
, s2ksalt
, s2kcount
,
703 rc
= merge_lists (protectedkey
, prot_begin
-protectedkey
, cleartext
,
704 sha1hash
, &final
, &finallen
);
705 /* Albeit cleartext has been allocated in secure memory and thus
706 xfree will wipe it out, we do an extra wipe just in case
707 somethings goes badly wrong. */
708 wipememory (cleartext
, n
);
713 rc
= calculate_mic (final
, sha1hash2
);
714 if (!rc
&& memcmp (sha1hash
, sha1hash2
, 20))
715 rc
= gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
718 wipememory (final
, finallen
);
724 *resultlen
= gcry_sexp_canon_len (final
, 0, NULL
, NULL
);
728 /* Check the type of the private key, this is one of the constants:
729 PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the
730 value 0), PRIVATE_KEY_CLEAR for an unprotected private key.
731 PRIVATE_KEY_PROTECTED for an protected private key or
732 PRIVATE_KEY_SHADOWED for a sub key where the secret parts are stored
735 agent_private_key_type (const unsigned char *privatekey
)
737 const unsigned char *s
;
742 return PRIVATE_KEY_UNKNOWN
;
746 return PRIVATE_KEY_UNKNOWN
;
747 if (smatch (&s
, n
, "protected-private-key"))
748 return PRIVATE_KEY_PROTECTED
;
749 if (smatch (&s
, n
, "shadowed-private-key"))
750 return PRIVATE_KEY_SHADOWED
;
751 if (smatch (&s
, n
, "private-key"))
752 return PRIVATE_KEY_CLEAR
;
753 return PRIVATE_KEY_UNKNOWN
;
758 /* Transform a passphrase into a suitable key of length KEYLEN and
759 store this key in the caller provided buffer KEY. The caller must
760 provide an HASHALGO, a valid S2KMODE (see rfc-2440) and depending on
761 that mode an S2KSALT of 8 random bytes and an S2KCOUNT (a suitable
764 Returns an error code on failure. */
766 hash_passphrase (const char *passphrase
, int hashalgo
,
768 const unsigned char *s2ksalt
,
769 unsigned long s2kcount
,
770 unsigned char *key
, size_t keylen
)
776 int pwlen
= strlen (passphrase
);
778 if ( (s2kmode
!= 0 && s2kmode
!= 1 && s2kmode
!= 3)
779 || !hashalgo
|| !keylen
|| !key
|| !passphrase
)
780 return gpg_error (GPG_ERR_INV_VALUE
);
781 if ((s2kmode
== 1 ||s2kmode
== 3) && !s2ksalt
)
782 return gpg_error (GPG_ERR_INV_VALUE
);
784 rc
= gcry_md_open (&md
, hashalgo
, GCRY_MD_FLAG_SECURE
);
788 for (pass
=0; used
< keylen
; pass
++)
793 for (i
=0; i
< pass
; i
++) /* preset the hash context */
794 gcry_md_putc (md
, 0);
797 if (s2kmode
== 1 || s2kmode
== 3)
799 int len2
= pwlen
+ 8;
800 unsigned long count
= len2
;
804 count
= (16ul + (s2kcount
& 15)) << ((s2kcount
>> 4) + 6);
811 gcry_md_write (md
, s2ksalt
, 8);
812 gcry_md_write (md
, passphrase
, pwlen
);
816 gcry_md_write (md
, s2ksalt
, count
);
819 gcry_md_write (md
, s2ksalt
, 8);
821 gcry_md_write (md
, passphrase
, count
);
825 gcry_md_write (md
, passphrase
, pwlen
);
828 i
= gcry_md_get_algo_dlen (hashalgo
);
829 if (i
> keylen
- used
)
831 memcpy (key
+used
, gcry_md_read (md
, hashalgo
), i
);
841 /* Create an canonical encoded S-expression with the shadow info from
842 a card's SERIALNO and the IDSTRING. */
844 make_shadow_info (const char *serialno
, const char *idstring
)
851 for (s
=serialno
, n
=0; *s
&& s
[1]; s
+= 2)
854 info
= p
= xtrymalloc (1 + 21 + n
855 + 21 + strlen (idstring
) + 1 + 1);
859 sprintf (numbuf
, "%d:", n
);
860 p
= stpcpy (p
, numbuf
);
861 for (s
=serialno
; *s
&& s
[1]; s
+= 2)
862 *(unsigned char *)p
++ = xtoi_2 (s
);
863 sprintf (numbuf
, "%d:", strlen (idstring
));
864 p
= stpcpy (p
, numbuf
);
865 p
= stpcpy (p
, idstring
);
868 return (unsigned char *)info
;
873 /* Create a shadow key from a public key. We use the shadow protocol
874 "ti-v1" and insert the S-expressionn SHADOW_INFO. The resulting
875 S-expression is returned in an allocated buffer RESULT will point
876 to. The input parameters are expected to be valid canonicalized
879 agent_shadow_key (const unsigned char *pubkey
,
880 const unsigned char *shadow_info
,
881 unsigned char **result
)
883 const unsigned char *s
;
884 const unsigned char *point
;
888 size_t pubkey_len
= gcry_sexp_canon_len (pubkey
, 0, NULL
,NULL
);
889 size_t shadow_info_len
= gcry_sexp_canon_len (shadow_info
, 0, NULL
,NULL
);
891 if (!pubkey_len
|| !shadow_info_len
)
892 return gpg_error (GPG_ERR_INV_VALUE
);
895 return gpg_error (GPG_ERR_INV_SEXP
);
900 return gpg_error (GPG_ERR_INV_SEXP
);
901 if (!smatch (&s
, n
, "public-key"))
902 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
904 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
909 return gpg_error (GPG_ERR_INV_SEXP
);
910 s
+= n
; /* skip over the algorithm name */
915 return gpg_error (GPG_ERR_INV_SEXP
);
920 return gpg_error (GPG_ERR_INV_SEXP
);
924 return gpg_error (GPG_ERR_INV_SEXP
);
925 s
+=n
; /* skip value */
927 return gpg_error (GPG_ERR_INV_SEXP
);
931 point
= s
; /* insert right before the point */
936 /* Calculate required length by taking in account: the "shadowed-"
937 prefix, the "shadowed", "t1-v1" as well as some parenthesis */
938 n
= 12 + pubkey_len
+ 1 + 3+8 + 2+5 + shadow_info_len
+ 1;
939 *result
= xtrymalloc (n
);
942 return out_of_core ();
943 p
= stpcpy (p
, "(20:shadowed-private-key");
944 /* (10:public-key ...)*/
945 memcpy (p
, pubkey
+14, point
- (pubkey
+14));
946 p
+= point
- (pubkey
+14);
947 p
= stpcpy (p
, "(8:shadowed5:t1-v1");
948 memcpy (p
, shadow_info
, shadow_info_len
);
949 p
+= shadow_info_len
;
951 memcpy (p
, point
, pubkey_len
- (point
- pubkey
));
952 p
+= pubkey_len
- (point
- pubkey
);
957 /* Parse a canonical encoded shadowed key and return a pointer to the
958 inner list with the shadow_info */
960 agent_get_shadow_info (const unsigned char *shadowkey
,
961 unsigned char const **shadow_info
)
963 const unsigned char *s
;
969 return gpg_error (GPG_ERR_INV_SEXP
);
974 return gpg_error (GPG_ERR_INV_SEXP
);
975 if (!smatch (&s
, n
, "shadowed-private-key"))
976 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
978 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
983 return gpg_error (GPG_ERR_INV_SEXP
);
984 s
+= n
; /* skip over the algorithm name */
989 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
991 return gpg_error (GPG_ERR_INV_SEXP
);
996 return gpg_error (GPG_ERR_INV_SEXP
);
997 if (smatch (&s
, n
, "shadowed"))
1002 return gpg_error (GPG_ERR_INV_SEXP
);
1003 s
+=n
; /* skip value */
1005 return gpg_error (GPG_ERR_INV_SEXP
);
1009 /* Found the shadowed list, S points to the protocol */
1012 return gpg_error (GPG_ERR_INV_SEXP
);
1013 if (smatch (&s
, n
, "t1-v1"))
1016 return gpg_error (GPG_ERR_INV_SEXP
);
1020 return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL
);