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 pint 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 ereturn 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 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
;
148 int saltpos
, ivpos
, encpos
;
150 rc
= gcry_cipher_open (&hd
, PROT_CIPHER
, GCRY_CIPHER_MODE_CBC
,
156 /* We need to work on a copy of the data because this makes it
157 easier to add the trailer and the padding and more important we
158 have to prefix the text with 2 parenthesis, so we have to
159 allocate enough space for:
161 ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
163 We always append a full block of random bytes as padding but
164 encrypt only what is needed for a full blocksize */
165 blklen
= gcry_cipher_get_algo_blklen (PROT_CIPHER
);
166 outlen
= 2 + protlen
+ 2 + 6 + 6 + 23 + 2 + blklen
;
167 enclen
= outlen
/blklen
* blklen
;
168 outbuf
= gcry_malloc_secure (outlen
);
173 /* Allocate random bytes to be used as IV, padding and s2k salt. */
174 iv
= xtrymalloc (blklen
*2+8);
176 rc
= gpg_error (GPG_ERR_ENOMEM
);
177 gcry_create_nonce (iv
, blklen
*2+8);
178 rc
= gcry_cipher_setiv (hd
, iv
, blklen
);
183 size_t keylen
= PROT_CIPHER_KEYLEN
;
185 key
= gcry_malloc_secure (keylen
);
190 rc
= hash_passphrase (passphrase
, GCRY_MD_SHA1
,
191 3, iv
+2*blklen
, 96, key
, keylen
);
193 rc
= gcry_cipher_setkey (hd
, key
, keylen
);
202 memcpy (p
, protbegin
, protlen
);
204 memcpy (p
, ")(4:hash4:sha120:", 17);
206 memcpy (p
, sha1hash
, 20);
210 memcpy (p
, iv
+blklen
, blklen
);
212 assert ( p
- outbuf
== outlen
);
213 rc
= gcry_cipher_encrypt (hd
, outbuf
, enclen
, NULL
, 0);
215 gcry_cipher_close (hd
);
223 /* Now allocate the buffer we want to return. This is
225 (protected openpgp-s2k3-sha1-aes-cbc
226 ((sha1 salt no_of_iterations) 16byte_iv)
227 encrypted_octet_string)
229 in canoncical format of course. We use asprintf and %n modifier
230 and spaces as palceholders. */
232 "(9:protected%d:%s((4:sha18:%n_8bytes_2:96)%d:%n%*s)%d:%n%*s)",
233 (int)strlen (modestr
), modestr
,
235 blklen
, &ivpos
, blklen
, "",
236 enclen
, &encpos
, enclen
, "");
238 { /* asprintf does not use our malloc system */
240 p
= xtrymalloc (strlen (psave
)+1);
247 gpg_error_t tmperr
= out_of_core ();
252 *resultlen
= strlen (p
);
254 memcpy (p
+saltpos
, iv
+2*blklen
, 8);
255 memcpy (p
+ivpos
, iv
, blklen
);
256 memcpy (p
+encpos
, outbuf
, enclen
);
264 /* Protect the key encoded in canonical format in plainkey. We assume
265 a valid S-Exp here. */
267 agent_protect (const unsigned char *plainkey
, const char *passphrase
,
268 unsigned char **result
, size_t *resultlen
)
271 const unsigned char *s
;
272 const unsigned char *hash_begin
, *hash_end
;
273 const unsigned char *prot_begin
, *prot_end
, *real_end
;
276 unsigned char hashvalue
[20];
277 unsigned char *protected;
284 return gpg_error (GPG_ERR_INV_SEXP
);
289 return gpg_error (GPG_ERR_INV_SEXP
);
290 if (!smatch (&s
, n
, "private-key"))
291 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
293 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
299 return gpg_error (GPG_ERR_INV_SEXP
);
301 for (infidx
=0; protect_info
[infidx
].algo
302 && !smatch (&s
, n
, protect_info
[infidx
].algo
); infidx
++)
304 if (!protect_info
[infidx
].algo
)
305 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM
);
307 prot_begin
= prot_end
= NULL
;
308 for (i
=0; (c
=protect_info
[infidx
].parmlist
[i
]); i
++)
310 if (i
== protect_info
[infidx
].prot_from
)
313 return gpg_error (GPG_ERR_INV_SEXP
);
318 return gpg_error (GPG_ERR_INV_SEXP
);
319 if (n
!= 1 || c
!= *s
)
320 return gpg_error (GPG_ERR_INV_SEXP
);
324 return gpg_error (GPG_ERR_INV_SEXP
);
325 s
+=n
; /* skip value */
327 return gpg_error (GPG_ERR_INV_SEXP
);
329 if (i
== protect_info
[infidx
].prot_to
)
333 if (*s
!= ')' || !prot_begin
|| !prot_end
)
334 return gpg_error (GPG_ERR_INV_SEXP
);
338 /* skip to the end of the S-exp */
340 rc
= sskip (&s
, &depth
);
346 gcry_md_hash_buffer (GCRY_MD_SHA1
, hashvalue
,
347 hash_begin
, hash_end
- hash_begin
+ 1);
349 rc
= do_encryption (prot_begin
, prot_end
- prot_begin
+ 1,
350 passphrase
, hashvalue
,
351 &protected, &protectedlen
);
355 /* Now create the protected version of the key. Note that the 10
356 extra bytes are for for the inserted "protected-" string (the
357 beginning of the plaintext reads: "((11:private-key(" ). */
359 + (prot_begin
-plainkey
)
361 + (real_end
-prot_end
));
362 *result
= p
= xtrymalloc (*resultlen
);
365 gpg_error_t tmperr
= out_of_core ();
369 memcpy (p
, "(21:protected-", 14);
371 memcpy (p
, plainkey
+4, prot_begin
- plainkey
- 4);
372 p
+= prot_begin
- plainkey
- 4;
373 memcpy (p
, protected, protectedlen
);
375 memcpy (p
, prot_end
+1, real_end
- prot_end
);
376 p
+= real_end
- prot_end
;
377 assert ( p
- *result
== *resultlen
);
383 /* Do the actual decryption and check the return list for consistency. */
385 do_decryption (const unsigned char *protected, size_t protectedlen
,
386 const char *passphrase
,
387 const unsigned char *s2ksalt
, unsigned long s2kcount
,
388 const unsigned char *iv
, size_t ivlen
,
389 unsigned char **result
)
394 unsigned char *outbuf
;
397 blklen
= gcry_cipher_get_algo_blklen (PROT_CIPHER
);
398 if (protectedlen
< 4 || (protectedlen
%blklen
))
399 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
401 rc
= gcry_cipher_open (&hd
, PROT_CIPHER
, GCRY_CIPHER_MODE_CBC
,
406 outbuf
= gcry_malloc_secure (protectedlen
);
410 rc
= gcry_cipher_setiv (hd
, iv
, ivlen
);
414 size_t keylen
= PROT_CIPHER_KEYLEN
;
416 key
= gcry_malloc_secure (keylen
);
421 rc
= hash_passphrase (passphrase
, GCRY_MD_SHA1
,
422 3, s2ksalt
, s2kcount
, key
, keylen
);
424 rc
= gcry_cipher_setkey (hd
, key
, keylen
);
429 rc
= gcry_cipher_decrypt (hd
, outbuf
, protectedlen
,
430 protected, protectedlen
);
431 gcry_cipher_close (hd
);
437 /* Do a quick check first. */
438 if (*outbuf
!= '(' && outbuf
[1] != '(')
441 return gpg_error (GPG_ERR_BAD_PASSPHRASE
);
443 /* Check that we have a consistent S-Exp. */
444 reallen
= gcry_sexp_canon_len (outbuf
, protectedlen
, NULL
, NULL
);
445 if (!reallen
|| (reallen
+ blklen
< protectedlen
) )
448 return gpg_error (GPG_ERR_BAD_PASSPHRASE
);
455 /* Merge the parameter list contained in CLEARTEXT with the original
456 protect lists PROTECTEDKEY by replacing the list at REPLACEPOS.
457 Return the new list in RESULT and the MIC value in the 20 byte
460 merge_lists (const unsigned char *protectedkey
,
462 const unsigned char *cleartext
,
463 unsigned char *sha1hash
,
464 unsigned char **result
, size_t *resultlen
)
466 size_t n
, newlistlen
;
467 unsigned char *newlist
, *p
;
468 const unsigned char *s
;
469 const unsigned char *startpos
, *endpos
;
473 return gpg_error (GPG_ERR_BUG
);
475 /* Estimate the required size of the resulting list. We have a large
476 safety margin of >20 bytes (MIC hash from CLEARTEXT and the
477 removed "protected-" */
478 newlistlen
= gcry_sexp_canon_len (protectedkey
, 0, NULL
, NULL
);
480 return gpg_error (GPG_ERR_BUG
);
481 n
= gcry_sexp_canon_len (cleartext
, 0, NULL
, NULL
);
483 return gpg_error (GPG_ERR_BUG
);
485 newlist
= gcry_malloc_secure (newlistlen
);
487 return out_of_core ();
489 /* Copy the initial segment */
490 strcpy (newlist
, "(11:private-key");
492 memcpy (p
, protectedkey
+15+10, replacepos
-15-10);
493 p
+= replacepos
-15-10;
495 /* copy the cleartext */
497 if (*s
!= '(' && s
[1] != '(')
498 return gpg_error (GPG_ERR_BUG
); /*we already checked this */
520 /* short intermezzo: Get the MIC */
525 if (!smatch (&s
, n
, "hash"))
528 if (!smatch (&s
, n
, "sha1"))
533 memcpy (sha1hash
, s
, 20);
539 /* append the parameter list */
540 memcpy (p
, startpos
, endpos
- startpos
);
541 p
+= endpos
- startpos
;
543 /* skip overt the protected list element in the original list */
544 s
= protectedkey
+ replacepos
;
552 i
= 2; /* we are inside this level */
556 assert (s
[-1] == ')');
557 endpos
= s
; /* one behind the end of the list */
559 /* append the rest */
560 memcpy (p
, startpos
, endpos
- startpos
);
561 p
+= endpos
- startpos
;
565 *resultlen
= newlistlen
;
569 wipememory (newlist
, newlistlen
);
574 wipememory (newlist
, newlistlen
);
576 return gpg_error (GPG_ERR_INV_SEXP
);
581 /* Unprotect the key encoded in canonical format. We assume a valid
584 agent_unprotect (const unsigned char *protectedkey
, const char *passphrase
,
585 unsigned char **result
, size_t *resultlen
)
588 const unsigned char *s
;
591 unsigned char sha1hash
[20], sha1hash2
[20];
592 const unsigned char *s2ksalt
;
593 unsigned long s2kcount
;
594 const unsigned char *iv
;
595 const unsigned char *prot_begin
;
596 unsigned char *cleartext
;
597 unsigned char *final
;
602 return gpg_error (GPG_ERR_INV_SEXP
);
606 return gpg_error (GPG_ERR_INV_SEXP
);
607 if (!smatch (&s
, n
, "protected-private-key"))
608 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
610 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
614 return gpg_error (GPG_ERR_INV_SEXP
);
616 for (infidx
=0; protect_info
[infidx
].algo
617 && !smatch (&s
, n
, protect_info
[infidx
].algo
); infidx
++)
619 if (!protect_info
[infidx
].algo
)
620 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM
);
622 /* Now find the list with the protected information. Here is an
623 example for such a list:
624 (protected openpgp-s2k3-sha1-aes-cbc
625 ((sha1 <salt> <count>) <Initialization_Vector>)
631 return gpg_error (GPG_ERR_INV_SEXP
);
636 return gpg_error (GPG_ERR_INV_SEXP
);
637 if (smatch (&s
, n
, "protected"))
648 return gpg_error (GPG_ERR_INV_SEXP
);
649 if (!smatch (&s
, n
, "openpgp-s2k3-sha1-" PROT_CIPHER_STRING
"-cbc"))
650 return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION
);
651 if (*s
!= '(' || s
[1] != '(')
652 return gpg_error (GPG_ERR_INV_SEXP
);
656 return gpg_error (GPG_ERR_INV_SEXP
);
657 if (!smatch (&s
, n
, "sha1"))
658 return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION
);
661 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
666 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
667 /* We expect a list close as next, so we can simply use strtoul()
668 here. We might want to check that we only have digits - but this
669 is nothing we should worry about */
671 return gpg_error (GPG_ERR_INV_SEXP
);
672 s2kcount
= strtoul (s
, NULL
, 10);
674 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
676 s
++; /* skip list end */
679 if (n
!= 16) /* Wrong blocksize for IV (we support only aes-128). */
680 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
684 return gpg_error (GPG_ERR_INV_SEXP
);
688 return gpg_error (GPG_ERR_INV_SEXP
);
690 rc
= do_decryption (s
, n
,
691 passphrase
, s2ksalt
, s2kcount
,
697 rc
= merge_lists (protectedkey
, prot_begin
-protectedkey
, cleartext
,
698 sha1hash
, &final
, &finallen
);
699 /* Albeit cleartext has been allocated in secure memory and thus
700 xfree will wipe it out, we do an extra wipe just in case
701 somethings goes badly wrong. */
702 wipememory (cleartext
, prot_begin
-protectedkey
);
707 rc
= calculate_mic (final
, sha1hash2
);
708 if (!rc
&& memcmp (sha1hash
, sha1hash2
, 20))
709 rc
= gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
712 wipememory (final
, finallen
);
718 *resultlen
= gcry_sexp_canon_len (final
, 0, NULL
, NULL
);
722 /* Check the type of the private key, this is one of the constants:
723 PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the
724 value 0), PRIVATE_KEY_CLEAR for an unprotected private key.
725 PRIVATE_KEY_PROTECTED for an protected private key or
726 PRIVATE_KEY_SHADOWED for a sub key where the secret parts are stored
729 agent_private_key_type (const unsigned char *privatekey
)
731 const unsigned char *s
;
736 return PRIVATE_KEY_UNKNOWN
;
740 return PRIVATE_KEY_UNKNOWN
;
741 if (smatch (&s
, n
, "protected-private-key"))
742 return PRIVATE_KEY_PROTECTED
;
743 if (smatch (&s
, n
, "shadowed-private-key"))
744 return PRIVATE_KEY_SHADOWED
;
745 if (smatch (&s
, n
, "private-key"))
746 return PRIVATE_KEY_CLEAR
;
747 return PRIVATE_KEY_UNKNOWN
;
752 /* Transform a passphrase into a suitable key of length KEYLEN and
753 store this key in the caller provided buffer KEY. The caller must
754 provide an HASHALGO, a valid S2KMODE (see rfc-2440) and depending on
755 that mode an S2KSALT of 8 random bytes and an S2KCOUNT (a suitable
758 Returns an error code on failure. */
760 hash_passphrase (const char *passphrase
, int hashalgo
,
762 const unsigned char *s2ksalt
,
763 unsigned long s2kcount
,
764 unsigned char *key
, size_t keylen
)
770 int pwlen
= strlen (passphrase
);
772 if ( (s2kmode
!= 0 && s2kmode
!= 1 && s2kmode
!= 3)
773 || !hashalgo
|| !keylen
|| !key
|| !passphrase
)
774 return gpg_error (GPG_ERR_INV_VALUE
);
775 if ((s2kmode
== 1 ||s2kmode
== 3) && !s2ksalt
)
776 return gpg_error (GPG_ERR_INV_VALUE
);
778 rc
= gcry_md_open (&md
, hashalgo
, GCRY_MD_FLAG_SECURE
);
782 for (pass
=0; used
< keylen
; pass
++)
787 for (i
=0; i
< pass
; i
++) /* preset the hash context */
788 gcry_md_putc (md
, 0);
791 if (s2kmode
== 1 || s2kmode
== 3)
793 int len2
= pwlen
+ 8;
794 unsigned long count
= len2
;
798 count
= (16ul + (s2kcount
& 15)) << ((s2kcount
>> 4) + 6);
805 gcry_md_write (md
, s2ksalt
, 8);
806 gcry_md_write (md
, passphrase
, pwlen
);
810 gcry_md_write (md
, s2ksalt
, count
);
813 gcry_md_write (md
, s2ksalt
, 8);
815 gcry_md_write (md
, passphrase
, count
);
819 gcry_md_write (md
, passphrase
, pwlen
);
822 i
= gcry_md_get_algo_dlen (hashalgo
);
823 if (i
> keylen
- used
)
825 memcpy (key
+used
, gcry_md_read (md
, hashalgo
), i
);
834 /* Create a shadow key from a public key. We use the shadow protocol
835 "ti-v1" and insert the S-expressionn SHADOW_INFO. The resulting
836 S-expression is returned in an allocated buffer RESULT will point
837 to. The input parameters are expected to be valid canonilized
840 agent_shadow_key (const unsigned char *pubkey
,
841 const unsigned char *shadow_info
,
842 unsigned char **result
)
844 const unsigned char *s
;
845 const unsigned char *point
;
849 size_t pubkey_len
= gcry_sexp_canon_len (pubkey
, 0, NULL
,NULL
);
850 size_t shadow_info_len
= gcry_sexp_canon_len (shadow_info
, 0, NULL
,NULL
);
852 if (!pubkey_len
|| !shadow_info_len
)
853 return gpg_error (GPG_ERR_INV_VALUE
);
856 return gpg_error (GPG_ERR_INV_SEXP
);
861 return gpg_error (GPG_ERR_INV_SEXP
);
862 if (!smatch (&s
, n
, "public-key"))
863 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
865 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
870 return gpg_error (GPG_ERR_INV_SEXP
);
871 s
+= n
; /* skip over the algorithm name */
876 return gpg_error (GPG_ERR_INV_SEXP
);
881 return gpg_error (GPG_ERR_INV_SEXP
);
885 return gpg_error (GPG_ERR_INV_SEXP
);
886 s
+=n
; /* skip value */
888 return gpg_error (GPG_ERR_INV_SEXP
);
892 point
= s
; /* insert right before the point */
897 /* calculate required length by taking in account: the "shadowed-"
898 prefix, the "shadowed", "t1-v1" as well as some parenthesis */
899 n
= 12 + pubkey_len
+ 1 + 3+8 + 2+5 + shadow_info_len
+ 1;
900 *result
= p
= xtrymalloc (n
);
902 return out_of_core ();
903 p
= stpcpy (p
, "(20:shadowed-private-key");
904 /* (10:public-key ...)*/
905 memcpy (p
, pubkey
+14, point
- (pubkey
+14));
906 p
+= point
- (pubkey
+14);
907 p
= stpcpy (p
, "(8:shadowed5:t1-v1");
908 memcpy (p
, shadow_info
, shadow_info_len
);
909 p
+= shadow_info_len
;
911 memcpy (p
, point
, pubkey_len
- (point
- pubkey
));
912 p
+= pubkey_len
- (point
- pubkey
);
917 /* Parse a canonical encoded shadowed key and return a pointer to the
918 inner list with the shadow_info */
920 agent_get_shadow_info (const unsigned char *shadowkey
,
921 unsigned char const **shadow_info
)
923 const unsigned char *s
;
929 return gpg_error (GPG_ERR_INV_SEXP
);
934 return gpg_error (GPG_ERR_INV_SEXP
);
935 if (!smatch (&s
, n
, "shadowed-private-key"))
936 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
938 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
943 return gpg_error (GPG_ERR_INV_SEXP
);
944 s
+= n
; /* skip over the algorithm name */
949 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
951 return gpg_error (GPG_ERR_INV_SEXP
);
956 return gpg_error (GPG_ERR_INV_SEXP
);
957 if (smatch (&s
, n
, "shadowed"))
962 return gpg_error (GPG_ERR_INV_SEXP
);
963 s
+=n
; /* skip value */
965 return gpg_error (GPG_ERR_INV_SEXP
);
969 /* Found the shadowed list, S points to the protocol */
972 return gpg_error (GPG_ERR_INV_SEXP
);
973 if (smatch (&s
, n
, "t1-v1"))
976 return gpg_error (GPG_ERR_INV_SEXP
);
980 return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL
);