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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
35 #include "sexp-parse.h"
37 #define PROT_CIPHER GCRY_CIPHER_AES
38 #define PROT_CIPHER_STRING "aes"
39 #define PROT_CIPHER_KEYLEN (128/8)
42 /* A table containing the information needed to create a protected
47 int prot_from
, prot_to
;
49 { "rsa", "nedpqu", 2, 5 },
50 { "dsa", "pqgyx", 4, 4 },
51 { "elg", "pgyx", 3, 3 },
57 hash_passphrase (const char *passphrase
, int hashalgo
,
59 const unsigned char *s2ksalt
, unsigned long s2kcount
,
60 unsigned char *key
, size_t keylen
);
64 /* Calculate the MIC for a private key S-Exp. SHA1HASH should point to
65 a 20 byte buffer. This function is suitable for any algorithms. */
67 calculate_mic (const unsigned char *plainkey
, unsigned char *sha1hash
)
69 const unsigned char *hash_begin
, *hash_end
;
70 const unsigned char *s
;
75 return gpg_error (GPG_ERR_INV_SEXP
);
79 return gpg_error (GPG_ERR_INV_SEXP
);
80 if (!smatch (&s
, n
, "private-key"))
81 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
83 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
88 return gpg_error (GPG_ERR_INV_SEXP
);
89 s
+= n
; /* skip over the algorithm name */
96 return gpg_error (GPG_ERR_INV_SEXP
);
100 return gpg_error (GPG_ERR_INV_SEXP
);
103 return gpg_error (GPG_ERR_INV_SEXP
);
107 return gpg_error (GPG_ERR_INV_SEXP
);
111 gcry_md_hash_buffer (GCRY_MD_SHA1
, sha1hash
,
112 hash_begin
, hash_end
- hash_begin
);
119 /* Encrypt the parameter block starting at PROTBEGIN with length
120 PROTLEN using the utf8 encoded key PASSPHRASE and return the entire
121 encrypted block in RESULT or return with an error code. SHA1HASH
122 is the 20 byte SHA-1 hash required for the integrity code.
124 The parameter block is expected to be an incomplete S-Expression of
125 the form (example in advanced format):
127 (d #046129F..[some bytes not shown]..81#)
128 (p #00e861b..[some bytes not shown]..f1#)
129 (q #00f7a7c..[some bytes not shown]..61#)
130 (u #304559a..[some bytes not shown]..9b#)
132 the returned block is the S-Expression:
134 (protected mode (parms) encrypted_octet_string)
138 do_encryption (const unsigned char *protbegin
, size_t protlen
,
139 const char *passphrase
, const unsigned char *sha1hash
,
140 unsigned char **result
, size_t *resultlen
)
143 const char *modestr
= "openpgp-s2k3-sha1-" PROT_CIPHER_STRING
"-cbc";
144 int blklen
, enclen
, outlen
;
145 unsigned char *iv
= NULL
;
149 int saltpos
, ivpos
, encpos
;
154 rc
= gcry_cipher_open (&hd
, PROT_CIPHER
, GCRY_CIPHER_MODE_CBC
,
160 /* We need to work on a copy of the data because this makes it
161 easier to add the trailer and the padding and more important we
162 have to prefix the text with 2 parenthesis, so we have to
163 allocate enough space for:
165 ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
167 We always append a full block of random bytes as padding but
168 encrypt only what is needed for a full blocksize */
169 blklen
= gcry_cipher_get_algo_blklen (PROT_CIPHER
);
170 outlen
= 2 + protlen
+ 2 + 6 + 6 + 23 + 2 + blklen
;
171 enclen
= outlen
/blklen
* blklen
;
172 outbuf
= gcry_malloc_secure (outlen
);
177 /* Allocate random bytes to be used as IV, padding and s2k salt. */
178 iv
= xtrymalloc (blklen
*2+8);
180 rc
= gpg_error (GPG_ERR_ENOMEM
);
181 gcry_create_nonce (iv
, blklen
*2+8);
182 rc
= gcry_cipher_setiv (hd
, iv
, blklen
);
187 size_t keylen
= PROT_CIPHER_KEYLEN
;
189 key
= gcry_malloc_secure (keylen
);
194 rc
= hash_passphrase (passphrase
, GCRY_MD_SHA1
,
195 3, iv
+2*blklen
, 96, key
, keylen
);
197 rc
= gcry_cipher_setkey (hd
, key
, keylen
);
206 memcpy (p
, protbegin
, protlen
);
208 memcpy (p
, ")(4:hash4:sha120:", 17);
210 memcpy (p
, sha1hash
, 20);
214 memcpy (p
, iv
+blklen
, blklen
);
216 assert ( p
- outbuf
== outlen
);
217 rc
= gcry_cipher_encrypt (hd
, outbuf
, enclen
, NULL
, 0);
219 gcry_cipher_close (hd
);
227 /* Now allocate the buffer we want to return. This is
229 (protected openpgp-s2k3-sha1-aes-cbc
230 ((sha1 salt no_of_iterations) 16byte_iv)
231 encrypted_octet_string)
233 in canoncical format of course. We use asprintf and %n modifier
234 and spaces as palceholders. */
236 "(9:protected%d:%s((4:sha18:%n_8bytes_2:96)%d:%n%*s)%d:%n%*s)",
237 (int)strlen (modestr
), modestr
,
239 blklen
, &ivpos
, blklen
, "",
240 enclen
, &encpos
, enclen
, "");
242 { /* asprintf does not use our malloc system */
244 p
= xtrymalloc (strlen (psave
)+1);
251 gpg_error_t tmperr
= out_of_core ();
256 *resultlen
= strlen (p
);
257 *result
= (unsigned char*)p
;
258 memcpy (p
+saltpos
, iv
+2*blklen
, 8);
259 memcpy (p
+ivpos
, iv
, blklen
);
260 memcpy (p
+encpos
, outbuf
, enclen
);
268 /* Protect the key encoded in canonical format in PLAINKEY. We assume
269 a valid S-Exp here. */
271 agent_protect (const unsigned char *plainkey
, const char *passphrase
,
272 unsigned char **result
, size_t *resultlen
)
275 const unsigned char *s
;
276 const unsigned char *hash_begin
, *hash_end
;
277 const unsigned char *prot_begin
, *prot_end
, *real_end
;
280 unsigned char hashvalue
[20];
281 unsigned char *protected;
288 return gpg_error (GPG_ERR_INV_SEXP
);
293 return gpg_error (GPG_ERR_INV_SEXP
);
294 if (!smatch (&s
, n
, "private-key"))
295 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
297 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
303 return gpg_error (GPG_ERR_INV_SEXP
);
305 for (infidx
=0; protect_info
[infidx
].algo
306 && !smatch (&s
, n
, protect_info
[infidx
].algo
); infidx
++)
308 if (!protect_info
[infidx
].algo
)
309 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM
);
311 prot_begin
= prot_end
= NULL
;
312 for (i
=0; (c
=protect_info
[infidx
].parmlist
[i
]); i
++)
314 if (i
== protect_info
[infidx
].prot_from
)
317 return gpg_error (GPG_ERR_INV_SEXP
);
322 return gpg_error (GPG_ERR_INV_SEXP
);
323 if (n
!= 1 || c
!= *s
)
324 return gpg_error (GPG_ERR_INV_SEXP
);
328 return gpg_error (GPG_ERR_INV_SEXP
);
329 s
+=n
; /* skip value */
331 return gpg_error (GPG_ERR_INV_SEXP
);
333 if (i
== protect_info
[infidx
].prot_to
)
337 if (*s
!= ')' || !prot_begin
|| !prot_end
)
338 return gpg_error (GPG_ERR_INV_SEXP
);
342 /* skip to the end of the S-exp */
344 rc
= sskip (&s
, &depth
);
350 gcry_md_hash_buffer (GCRY_MD_SHA1
, hashvalue
,
351 hash_begin
, hash_end
- hash_begin
+ 1);
353 rc
= do_encryption (prot_begin
, prot_end
- prot_begin
+ 1,
354 passphrase
, hashvalue
,
355 &protected, &protectedlen
);
359 /* Now create the protected version of the key. Note that the 10
360 extra bytes are for for the inserted "protected-" string (the
361 beginning of the plaintext reads: "((11:private-key(" ). */
363 + (prot_begin
-plainkey
)
365 + (real_end
-prot_end
));
366 *result
= p
= xtrymalloc (*resultlen
);
369 gpg_error_t tmperr
= out_of_core ();
373 memcpy (p
, "(21:protected-", 14);
375 memcpy (p
, plainkey
+4, prot_begin
- plainkey
- 4);
376 p
+= prot_begin
- plainkey
- 4;
377 memcpy (p
, protected, protectedlen
);
379 memcpy (p
, prot_end
+1, real_end
- prot_end
);
380 p
+= real_end
- prot_end
;
381 assert ( p
- *result
== *resultlen
);
387 /* Do the actual decryption and check the return list for consistency. */
389 do_decryption (const unsigned char *protected, size_t protectedlen
,
390 const char *passphrase
,
391 const unsigned char *s2ksalt
, unsigned long s2kcount
,
392 const unsigned char *iv
, size_t ivlen
,
393 unsigned char **result
)
398 unsigned char *outbuf
;
401 blklen
= gcry_cipher_get_algo_blklen (PROT_CIPHER
);
402 if (protectedlen
< 4 || (protectedlen
%blklen
))
403 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
405 rc
= gcry_cipher_open (&hd
, PROT_CIPHER
, GCRY_CIPHER_MODE_CBC
,
410 outbuf
= gcry_malloc_secure (protectedlen
);
414 rc
= gcry_cipher_setiv (hd
, iv
, ivlen
);
418 size_t keylen
= PROT_CIPHER_KEYLEN
;
420 key
= gcry_malloc_secure (keylen
);
425 rc
= hash_passphrase (passphrase
, GCRY_MD_SHA1
,
426 3, s2ksalt
, s2kcount
, key
, keylen
);
428 rc
= gcry_cipher_setkey (hd
, key
, keylen
);
433 rc
= gcry_cipher_decrypt (hd
, outbuf
, protectedlen
,
434 protected, protectedlen
);
435 gcry_cipher_close (hd
);
441 /* Do a quick check first. */
442 if (*outbuf
!= '(' && outbuf
[1] != '(')
445 return gpg_error (GPG_ERR_BAD_PASSPHRASE
);
447 /* Check that we have a consistent S-Exp. */
448 reallen
= gcry_sexp_canon_len (outbuf
, protectedlen
, NULL
, NULL
);
449 if (!reallen
|| (reallen
+ blklen
< protectedlen
) )
452 return gpg_error (GPG_ERR_BAD_PASSPHRASE
);
459 /* Merge the parameter list contained in CLEARTEXT with the original
460 protect lists PROTECTEDKEY by replacing the list at REPLACEPOS.
461 Return the new list in RESULT and the MIC value in the 20 byte
464 merge_lists (const unsigned char *protectedkey
,
466 const unsigned char *cleartext
,
467 unsigned char *sha1hash
,
468 unsigned char **result
, size_t *resultlen
)
470 size_t n
, newlistlen
;
471 unsigned char *newlist
, *p
;
472 const unsigned char *s
;
473 const unsigned char *startpos
, *endpos
;
480 return gpg_error (GPG_ERR_BUG
);
482 /* Estimate the required size of the resulting list. We have a large
483 safety margin of >20 bytes (MIC hash from CLEARTEXT and the
484 removed "protected-" */
485 newlistlen
= gcry_sexp_canon_len (protectedkey
, 0, NULL
, NULL
);
487 return gpg_error (GPG_ERR_BUG
);
488 n
= gcry_sexp_canon_len (cleartext
, 0, NULL
, NULL
);
490 return gpg_error (GPG_ERR_BUG
);
492 newlist
= gcry_malloc_secure (newlistlen
);
494 return out_of_core ();
496 /* Copy the initial segment */
497 strcpy ((char*)newlist
, "(11:private-key");
499 memcpy (p
, protectedkey
+15+10, replacepos
-15-10);
500 p
+= replacepos
-15-10;
502 /* copy the cleartext */
504 if (*s
!= '(' && s
[1] != '(')
505 return gpg_error (GPG_ERR_BUG
); /*we already checked this */
527 /* short intermezzo: Get the MIC */
532 if (!smatch (&s
, n
, "hash"))
535 if (!smatch (&s
, n
, "sha1"))
540 memcpy (sha1hash
, s
, 20);
546 /* append the parameter list */
547 memcpy (p
, startpos
, endpos
- startpos
);
548 p
+= endpos
- startpos
;
550 /* skip overt the protected list element in the original list */
551 s
= protectedkey
+ replacepos
;
559 i
= 2; /* we are inside this level */
563 assert (s
[-1] == ')');
564 endpos
= s
; /* one behind the end of the list */
566 /* append the rest */
567 memcpy (p
, startpos
, endpos
- startpos
);
568 p
+= endpos
- startpos
;
572 *resultlen
= newlistlen
;
576 wipememory (newlist
, newlistlen
);
581 wipememory (newlist
, newlistlen
);
583 return gpg_error (GPG_ERR_INV_SEXP
);
588 /* Unprotect the key encoded in canonical format. We assume a valid
591 agent_unprotect (const unsigned char *protectedkey
, const char *passphrase
,
592 unsigned char **result
, size_t *resultlen
)
595 const unsigned char *s
;
598 unsigned char sha1hash
[20], sha1hash2
[20];
599 const unsigned char *s2ksalt
;
600 unsigned long s2kcount
;
601 const unsigned char *iv
;
602 const unsigned char *prot_begin
;
603 unsigned char *cleartext
;
604 unsigned char *final
;
609 return gpg_error (GPG_ERR_INV_SEXP
);
613 return gpg_error (GPG_ERR_INV_SEXP
);
614 if (!smatch (&s
, n
, "protected-private-key"))
615 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
617 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
621 return gpg_error (GPG_ERR_INV_SEXP
);
623 for (infidx
=0; protect_info
[infidx
].algo
624 && !smatch (&s
, n
, protect_info
[infidx
].algo
); infidx
++)
626 if (!protect_info
[infidx
].algo
)
627 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM
);
629 /* Now find the list with the protected information. Here is an
630 example for such a list:
631 (protected openpgp-s2k3-sha1-aes-cbc
632 ((sha1 <salt> <count>) <Initialization_Vector>)
638 return gpg_error (GPG_ERR_INV_SEXP
);
643 return gpg_error (GPG_ERR_INV_SEXP
);
644 if (smatch (&s
, n
, "protected"))
655 return gpg_error (GPG_ERR_INV_SEXP
);
656 if (!smatch (&s
, n
, "openpgp-s2k3-sha1-" PROT_CIPHER_STRING
"-cbc"))
657 return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION
);
658 if (*s
!= '(' || s
[1] != '(')
659 return gpg_error (GPG_ERR_INV_SEXP
);
663 return gpg_error (GPG_ERR_INV_SEXP
);
664 if (!smatch (&s
, n
, "sha1"))
665 return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION
);
668 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
673 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
674 /* We expect a list close as next, so we can simply use strtoul()
675 here. We might want to check that we only have digits - but this
676 is nothing we should worry about */
678 return gpg_error (GPG_ERR_INV_SEXP
);
679 s2kcount
= strtoul ((const char*)s
, NULL
, 10);
681 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
683 s
++; /* skip list end */
686 if (n
!= 16) /* Wrong blocksize for IV (we support only aes-128). */
687 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
691 return gpg_error (GPG_ERR_INV_SEXP
);
695 return gpg_error (GPG_ERR_INV_SEXP
);
697 rc
= do_decryption (s
, n
,
698 passphrase
, s2ksalt
, s2kcount
,
704 rc
= merge_lists (protectedkey
, prot_begin
-protectedkey
, cleartext
,
705 sha1hash
, &final
, &finallen
);
706 /* Albeit cleartext has been allocated in secure memory and thus
707 xfree will wipe it out, we do an extra wipe just in case
708 somethings goes badly wrong. */
709 wipememory (cleartext
, n
);
714 rc
= calculate_mic (final
, sha1hash2
);
715 if (!rc
&& memcmp (sha1hash
, sha1hash2
, 20))
716 rc
= gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
719 wipememory (final
, finallen
);
725 *resultlen
= gcry_sexp_canon_len (final
, 0, NULL
, NULL
);
729 /* Check the type of the private key, this is one of the constants:
730 PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the
731 value 0), PRIVATE_KEY_CLEAR for an unprotected private key.
732 PRIVATE_KEY_PROTECTED for an protected private key or
733 PRIVATE_KEY_SHADOWED for a sub key where the secret parts are stored
736 agent_private_key_type (const unsigned char *privatekey
)
738 const unsigned char *s
;
743 return PRIVATE_KEY_UNKNOWN
;
747 return PRIVATE_KEY_UNKNOWN
;
748 if (smatch (&s
, n
, "protected-private-key"))
749 return PRIVATE_KEY_PROTECTED
;
750 if (smatch (&s
, n
, "shadowed-private-key"))
751 return PRIVATE_KEY_SHADOWED
;
752 if (smatch (&s
, n
, "private-key"))
753 return PRIVATE_KEY_CLEAR
;
754 return PRIVATE_KEY_UNKNOWN
;
759 /* Transform a passphrase into a suitable key of length KEYLEN and
760 store this key in the caller provided buffer KEY. The caller must
761 provide an HASHALGO, a valid S2KMODE (see rfc-2440) and depending on
762 that mode an S2KSALT of 8 random bytes and an S2KCOUNT (a suitable
765 Returns an error code on failure. */
767 hash_passphrase (const char *passphrase
, int hashalgo
,
769 const unsigned char *s2ksalt
,
770 unsigned long s2kcount
,
771 unsigned char *key
, size_t keylen
)
777 int pwlen
= strlen (passphrase
);
779 if ( (s2kmode
!= 0 && s2kmode
!= 1 && s2kmode
!= 3)
780 || !hashalgo
|| !keylen
|| !key
|| !passphrase
)
781 return gpg_error (GPG_ERR_INV_VALUE
);
782 if ((s2kmode
== 1 ||s2kmode
== 3) && !s2ksalt
)
783 return gpg_error (GPG_ERR_INV_VALUE
);
785 rc
= gcry_md_open (&md
, hashalgo
, GCRY_MD_FLAG_SECURE
);
789 for (pass
=0; used
< keylen
; pass
++)
794 for (i
=0; i
< pass
; i
++) /* preset the hash context */
795 gcry_md_putc (md
, 0);
798 if (s2kmode
== 1 || s2kmode
== 3)
800 int len2
= pwlen
+ 8;
801 unsigned long count
= len2
;
805 count
= (16ul + (s2kcount
& 15)) << ((s2kcount
>> 4) + 6);
812 gcry_md_write (md
, s2ksalt
, 8);
813 gcry_md_write (md
, passphrase
, pwlen
);
817 gcry_md_write (md
, s2ksalt
, count
);
820 gcry_md_write (md
, s2ksalt
, 8);
822 gcry_md_write (md
, passphrase
, count
);
826 gcry_md_write (md
, passphrase
, pwlen
);
829 i
= gcry_md_get_algo_dlen (hashalgo
);
830 if (i
> keylen
- used
)
832 memcpy (key
+used
, gcry_md_read (md
, hashalgo
), i
);
842 /* Create an canonical encoded S-expression with the shadow info from
843 a card's SERIALNO and the IDSTRING. */
845 make_shadow_info (const char *serialno
, const char *idstring
)
852 for (s
=serialno
, n
=0; *s
&& s
[1]; s
+= 2)
855 info
= p
= xtrymalloc (1 + 21 + n
856 + 21 + strlen (idstring
) + 1 + 1);
860 sprintf (numbuf
, "%d:", n
);
861 p
= stpcpy (p
, numbuf
);
862 for (s
=serialno
; *s
&& s
[1]; s
+= 2)
863 *(unsigned char *)p
++ = xtoi_2 (s
);
864 sprintf (numbuf
, "%u:", (unsigned int)strlen (idstring
));
865 p
= stpcpy (p
, numbuf
);
866 p
= stpcpy (p
, idstring
);
869 return (unsigned char *)info
;
874 /* Create a shadow key from a public key. We use the shadow protocol
875 "ti-v1" and insert the S-expressionn SHADOW_INFO. The resulting
876 S-expression is returned in an allocated buffer RESULT will point
877 to. The input parameters are expected to be valid canonicalized
880 agent_shadow_key (const unsigned char *pubkey
,
881 const unsigned char *shadow_info
,
882 unsigned char **result
)
884 const unsigned char *s
;
885 const unsigned char *point
;
889 size_t pubkey_len
= gcry_sexp_canon_len (pubkey
, 0, NULL
,NULL
);
890 size_t shadow_info_len
= gcry_sexp_canon_len (shadow_info
, 0, NULL
,NULL
);
892 if (!pubkey_len
|| !shadow_info_len
)
893 return gpg_error (GPG_ERR_INV_VALUE
);
896 return gpg_error (GPG_ERR_INV_SEXP
);
901 return gpg_error (GPG_ERR_INV_SEXP
);
902 if (!smatch (&s
, n
, "public-key"))
903 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
905 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
910 return gpg_error (GPG_ERR_INV_SEXP
);
911 s
+= n
; /* skip over the algorithm name */
916 return gpg_error (GPG_ERR_INV_SEXP
);
921 return gpg_error (GPG_ERR_INV_SEXP
);
925 return gpg_error (GPG_ERR_INV_SEXP
);
926 s
+=n
; /* skip value */
928 return gpg_error (GPG_ERR_INV_SEXP
);
932 point
= s
; /* insert right before the point */
937 /* Calculate required length by taking in account: the "shadowed-"
938 prefix, the "shadowed", "t1-v1" as well as some parenthesis */
939 n
= 12 + pubkey_len
+ 1 + 3+8 + 2+5 + shadow_info_len
+ 1;
940 *result
= xtrymalloc (n
);
943 return out_of_core ();
944 p
= stpcpy (p
, "(20:shadowed-private-key");
945 /* (10:public-key ...)*/
946 memcpy (p
, pubkey
+14, point
- (pubkey
+14));
947 p
+= point
- (pubkey
+14);
948 p
= stpcpy (p
, "(8:shadowed5:t1-v1");
949 memcpy (p
, shadow_info
, shadow_info_len
);
950 p
+= shadow_info_len
;
952 memcpy (p
, point
, pubkey_len
- (point
- pubkey
));
953 p
+= pubkey_len
- (point
- pubkey
);
958 /* Parse a canonical encoded shadowed key and return a pointer to the
959 inner list with the shadow_info */
961 agent_get_shadow_info (const unsigned char *shadowkey
,
962 unsigned char const **shadow_info
)
964 const unsigned char *s
;
970 return gpg_error (GPG_ERR_INV_SEXP
);
975 return gpg_error (GPG_ERR_INV_SEXP
);
976 if (!smatch (&s
, n
, "shadowed-private-key"))
977 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
979 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
984 return gpg_error (GPG_ERR_INV_SEXP
);
985 s
+= n
; /* skip over the algorithm name */
990 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
992 return gpg_error (GPG_ERR_INV_SEXP
);
997 return gpg_error (GPG_ERR_INV_SEXP
);
998 if (smatch (&s
, n
, "shadowed"))
1003 return gpg_error (GPG_ERR_INV_SEXP
);
1004 s
+=n
; /* skip value */
1006 return gpg_error (GPG_ERR_INV_SEXP
);
1010 /* Found the shadowed list, S points to the protocol */
1013 return gpg_error (GPG_ERR_INV_SEXP
);
1014 if (smatch (&s
, n
, "t1-v1"))
1017 return gpg_error (GPG_ERR_INV_SEXP
);
1021 return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL
);