1 /* protect.c - Un/Protect a secret key
2 * Copyright (C) 1998, 1999, 2000, 2001, 2002,
3 * 2003, 2007, 2009 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 3 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, see <http://www.gnu.org/licenses/>.
33 #include "sexp-parse.h"
35 #define PROT_CIPHER GCRY_CIPHER_AES
36 #define PROT_CIPHER_STRING "aes"
37 #define PROT_CIPHER_KEYLEN (128/8)
40 /* A table containing the information needed to create a protected
45 int prot_from
, prot_to
;
47 { "rsa", "nedpqu", 2, 5 },
48 { "dsa", "pqgyx", 4, 4 },
49 { "elg", "pgyx", 3, 3 },
55 hash_passphrase (const char *passphrase
, int hashalgo
,
57 const unsigned char *s2ksalt
, unsigned long s2kcount
,
58 unsigned char *key
, size_t keylen
);
62 /* Calculate the MIC for a private key S-Exp. SHA1HASH should point to
63 a 20 byte buffer. This function is suitable for any algorithms. */
65 calculate_mic (const unsigned char *plainkey
, unsigned char *sha1hash
)
67 const unsigned char *hash_begin
, *hash_end
;
68 const unsigned char *s
;
73 return gpg_error (GPG_ERR_INV_SEXP
);
77 return gpg_error (GPG_ERR_INV_SEXP
);
78 if (!smatch (&s
, n
, "private-key"))
79 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
81 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
86 return gpg_error (GPG_ERR_INV_SEXP
);
87 s
+= n
; /* skip over the algorithm name */
94 return gpg_error (GPG_ERR_INV_SEXP
);
98 return gpg_error (GPG_ERR_INV_SEXP
);
101 return gpg_error (GPG_ERR_INV_SEXP
);
105 return gpg_error (GPG_ERR_INV_SEXP
);
109 gcry_md_hash_buffer (GCRY_MD_SHA1
, sha1hash
,
110 hash_begin
, hash_end
- hash_begin
);
117 /* Encrypt the parameter block starting at PROTBEGIN with length
118 PROTLEN using the utf8 encoded key PASSPHRASE and return the entire
119 encrypted block in RESULT or return with an error code. SHA1HASH
120 is the 20 byte SHA-1 hash required for the integrity code.
122 The parameter block is expected to be an incomplete S-Expression of
123 the form (example in advanced format):
125 (d #046129F..[some bytes not shown]..81#)
126 (p #00e861b..[some bytes not shown]..f1#)
127 (q #00f7a7c..[some bytes not shown]..61#)
128 (u #304559a..[some bytes not shown]..9b#)
130 the returned block is the S-Expression:
132 (protected mode (parms) encrypted_octet_string)
136 do_encryption (const unsigned char *protbegin
, size_t protlen
,
137 const char *passphrase
, const unsigned char *sha1hash
,
138 unsigned char **result
, size_t *resultlen
)
141 const char *modestr
= "openpgp-s2k3-sha1-" PROT_CIPHER_STRING
"-cbc";
142 int blklen
, enclen
, outlen
;
143 unsigned char *iv
= NULL
;
147 int saltpos
, ivpos
, encpos
;
152 rc
= gcry_cipher_open (&hd
, PROT_CIPHER
, GCRY_CIPHER_MODE_CBC
,
158 /* We need to work on a copy of the data because this makes it
159 easier to add the trailer and the padding and more important we
160 have to prefix the text with 2 parenthesis, so we have to
161 allocate enough space for:
163 ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
165 We always append a full block of random bytes as padding but
166 encrypt only what is needed for a full blocksize. */
167 blklen
= gcry_cipher_get_algo_blklen (PROT_CIPHER
);
168 outlen
= 2 + protlen
+ 2 + 6 + 6 + 23 + 2 + blklen
;
169 enclen
= outlen
/blklen
* blklen
;
170 outbuf
= gcry_malloc_secure (outlen
);
175 /* Allocate random bytes to be used as IV, padding and s2k salt. */
176 iv
= xtrymalloc (blklen
*2+8);
178 rc
= gpg_error (GPG_ERR_ENOMEM
);
181 gcry_create_nonce (iv
, blklen
*2+8);
182 rc
= gcry_cipher_setiv (hd
, iv
, blklen
);
188 size_t keylen
= PROT_CIPHER_KEYLEN
;
190 key
= gcry_malloc_secure (keylen
);
195 rc
= hash_passphrase (passphrase
, GCRY_MD_SHA1
,
196 3, iv
+2*blklen
, 96, key
, keylen
);
198 rc
= gcry_cipher_setkey (hd
, key
, keylen
);
207 memcpy (p
, protbegin
, protlen
);
209 memcpy (p
, ")(4:hash4:sha120:", 17);
211 memcpy (p
, sha1hash
, 20);
215 memcpy (p
, iv
+blklen
, blklen
);
217 assert ( p
- outbuf
== outlen
);
218 rc
= gcry_cipher_encrypt (hd
, outbuf
, enclen
, NULL
, 0);
220 gcry_cipher_close (hd
);
228 /* Now allocate the buffer we want to return. This is
230 (protected openpgp-s2k3-sha1-aes-cbc
231 ((sha1 salt no_of_iterations) 16byte_iv)
232 encrypted_octet_string)
234 in canoncical format of course. We use asprintf and %n modifier
235 and dummy values as placeholders. */
237 ("(9:protected%d:%s((4:sha18:%n_8bytes_2:96)%d:%n%*s)%d:%n%*s)",
238 (int)strlen (modestr
), modestr
,
240 blklen
, &ivpos
, blklen
, "",
241 enclen
, &encpos
, enclen
, "");
244 gpg_error_t tmperr
= out_of_core ();
249 *resultlen
= strlen (p
);
250 *result
= (unsigned char*)p
;
251 memcpy (p
+saltpos
, iv
+2*blklen
, 8);
252 memcpy (p
+ivpos
, iv
, blklen
);
253 memcpy (p
+encpos
, outbuf
, enclen
);
261 /* Protect the key encoded in canonical format in PLAINKEY. We assume
262 a valid S-Exp here. */
264 agent_protect (const unsigned char *plainkey
, const char *passphrase
,
265 unsigned char **result
, size_t *resultlen
)
268 const unsigned char *s
;
269 const unsigned char *hash_begin
, *hash_end
;
270 const unsigned char *prot_begin
, *prot_end
, *real_end
;
273 unsigned char hashvalue
[20];
274 char timestamp_exp
[35];
275 unsigned char *protected;
281 /* Create an S-expression with the procted-at timestamp. */
282 memcpy (timestamp_exp
, "(12:protected-at15:", 19);
283 gnupg_get_isotime (timestamp_exp
+19);
284 timestamp_exp
[19+15] = ')';
286 /* Parse original key. */
289 return gpg_error (GPG_ERR_INV_SEXP
);
294 return gpg_error (GPG_ERR_INV_SEXP
);
295 if (!smatch (&s
, n
, "private-key"))
296 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
298 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
304 return gpg_error (GPG_ERR_INV_SEXP
);
306 for (infidx
=0; protect_info
[infidx
].algo
307 && !smatch (&s
, n
, protect_info
[infidx
].algo
); infidx
++)
309 if (!protect_info
[infidx
].algo
)
310 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM
);
312 prot_begin
= prot_end
= NULL
;
313 for (i
=0; (c
=protect_info
[infidx
].parmlist
[i
]); i
++)
315 if (i
== protect_info
[infidx
].prot_from
)
318 return gpg_error (GPG_ERR_INV_SEXP
);
323 return gpg_error (GPG_ERR_INV_SEXP
);
324 if (n
!= 1 || c
!= *s
)
325 return gpg_error (GPG_ERR_INV_SEXP
);
329 return gpg_error (GPG_ERR_INV_SEXP
);
330 s
+=n
; /* skip value */
332 return gpg_error (GPG_ERR_INV_SEXP
);
334 if (i
== protect_info
[infidx
].prot_to
)
338 if (*s
!= ')' || !prot_begin
|| !prot_end
)
339 return gpg_error (GPG_ERR_INV_SEXP
);
343 /* skip to the end of the S-exp */
345 rc
= sskip (&s
, &depth
);
352 /* Hash the stuff. Because the timestamp_exp won't get protected,
353 we can't simply hash a continuous buffer but need to use several
355 rc
= gcry_md_open (&md
, GCRY_MD_SHA1
, 0 );
358 gcry_md_write (md
, hash_begin
, hash_end
- hash_begin
);
359 gcry_md_write (md
, timestamp_exp
, 35);
360 gcry_md_write (md
, ")", 1);
361 memcpy (hashvalue
, gcry_md_read (md
, GCRY_MD_SHA1
), 20);
364 rc
= do_encryption (prot_begin
, prot_end
- prot_begin
+ 1,
365 passphrase
, hashvalue
,
366 &protected, &protectedlen
);
370 /* Now create the protected version of the key. Note that the 10
371 extra bytes are for for the inserted "protected-" string (the
372 beginning of the plaintext reads: "((11:private-key(" ). The 35
373 term is the space for (12:protected-at15:<timestamp>). */
375 + (prot_begin
-plainkey
)
378 + (real_end
-prot_end
));
379 *result
= p
= xtrymalloc (*resultlen
);
382 gpg_error_t tmperr
= out_of_core ();
386 memcpy (p
, "(21:protected-", 14);
388 memcpy (p
, plainkey
+4, prot_begin
- plainkey
- 4);
389 p
+= prot_begin
- plainkey
- 4;
390 memcpy (p
, protected, protectedlen
);
393 memcpy (p
, timestamp_exp
, 35);
396 memcpy (p
, prot_end
+1, real_end
- prot_end
);
397 p
+= real_end
- prot_end
;
398 assert ( p
- *result
== *resultlen
);
405 /* Do the actual decryption and check the return list for consistency. */
407 do_decryption (const unsigned char *protected, size_t protectedlen
,
408 const char *passphrase
,
409 const unsigned char *s2ksalt
, unsigned long s2kcount
,
410 const unsigned char *iv
, size_t ivlen
,
411 unsigned char **result
)
416 unsigned char *outbuf
;
419 blklen
= gcry_cipher_get_algo_blklen (PROT_CIPHER
);
420 if (protectedlen
< 4 || (protectedlen
%blklen
))
421 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
423 rc
= gcry_cipher_open (&hd
, PROT_CIPHER
, GCRY_CIPHER_MODE_CBC
,
428 outbuf
= gcry_malloc_secure (protectedlen
);
432 rc
= gcry_cipher_setiv (hd
, iv
, ivlen
);
436 size_t keylen
= PROT_CIPHER_KEYLEN
;
438 key
= gcry_malloc_secure (keylen
);
443 rc
= hash_passphrase (passphrase
, GCRY_MD_SHA1
,
444 3, s2ksalt
, s2kcount
, key
, keylen
);
446 rc
= gcry_cipher_setkey (hd
, key
, keylen
);
451 rc
= gcry_cipher_decrypt (hd
, outbuf
, protectedlen
,
452 protected, protectedlen
);
453 gcry_cipher_close (hd
);
459 /* Do a quick check first. */
460 if (*outbuf
!= '(' && outbuf
[1] != '(')
463 return gpg_error (GPG_ERR_BAD_PASSPHRASE
);
465 /* Check that we have a consistent S-Exp. */
466 reallen
= gcry_sexp_canon_len (outbuf
, protectedlen
, NULL
, NULL
);
467 if (!reallen
|| (reallen
+ blklen
< protectedlen
) )
470 return gpg_error (GPG_ERR_BAD_PASSPHRASE
);
477 /* Merge the parameter list contained in CLEARTEXT with the original
478 protect lists PROTECTEDKEY by replacing the list at REPLACEPOS.
479 Return the new list in RESULT and the MIC value in the 20 byte
480 buffer SHA1HASH. CUTOFF and CUTLEN will receive the offset and the
481 length of the resulting list which should go into the MIC
482 calculation but then be removed. */
484 merge_lists (const unsigned char *protectedkey
,
486 const unsigned char *cleartext
,
487 unsigned char *sha1hash
,
488 unsigned char **result
, size_t *resultlen
,
489 size_t *cutoff
, size_t *cutlen
)
491 size_t n
, newlistlen
;
492 unsigned char *newlist
, *p
;
493 const unsigned char *s
;
494 const unsigned char *startpos
, *endpos
;
503 return gpg_error (GPG_ERR_BUG
);
505 /* Estimate the required size of the resulting list. We have a large
506 safety margin of >20 bytes (MIC hash from CLEARTEXT and the
507 removed "protected-" */
508 newlistlen
= gcry_sexp_canon_len (protectedkey
, 0, NULL
, NULL
);
510 return gpg_error (GPG_ERR_BUG
);
511 n
= gcry_sexp_canon_len (cleartext
, 0, NULL
, NULL
);
513 return gpg_error (GPG_ERR_BUG
);
515 newlist
= gcry_malloc_secure (newlistlen
);
517 return out_of_core ();
519 /* Copy the initial segment */
520 strcpy ((char*)newlist
, "(11:private-key");
522 memcpy (p
, protectedkey
+15+10, replacepos
-15-10);
523 p
+= replacepos
-15-10;
525 /* copy the cleartext */
527 if (*s
!= '(' && s
[1] != '(')
528 return gpg_error (GPG_ERR_BUG
); /*we already checked this */
550 /* Intermezzo: Get the MIC */
555 if (!smatch (&s
, n
, "hash"))
558 if (!smatch (&s
, n
, "sha1"))
563 memcpy (sha1hash
, s
, 20);
569 /* append the parameter list */
570 memcpy (p
, startpos
, endpos
- startpos
);
571 p
+= endpos
- startpos
;
573 /* Skip over the protected list element in the original list. */
574 s
= protectedkey
+ replacepos
;
581 /* Record the position of the optional protected-at expression. */
584 const unsigned char *save_s
= s
;
587 if (smatch (&s
, n
, "protected-at"))
593 *cutlen
= s
- save_s
;
598 i
= 2; /* we are inside this level */
602 assert (s
[-1] == ')');
603 endpos
= s
; /* one behind the end of the list */
605 /* Append the rest. */
607 *cutoff
= p
- newlist
;
608 memcpy (p
, startpos
, endpos
- startpos
);
609 p
+= endpos
- startpos
;
614 *resultlen
= newlistlen
;
618 wipememory (newlist
, newlistlen
);
623 wipememory (newlist
, newlistlen
);
625 return gpg_error (GPG_ERR_INV_SEXP
);
630 /* Unprotect the key encoded in canonical format. We assume a valid
631 S-Exp here. If a protected-at item is available, its value will
632 be stored at protocted_at unless this is NULL. */
634 agent_unprotect (const unsigned char *protectedkey
, const char *passphrase
,
635 gnupg_isotime_t protected_at
,
636 unsigned char **result
, size_t *resultlen
)
639 const unsigned char *s
;
640 const unsigned char *protect_list
;
643 unsigned char sha1hash
[20], sha1hash2
[20];
644 const unsigned char *s2ksalt
;
645 unsigned long s2kcount
;
646 const unsigned char *iv
;
647 const unsigned char *prot_begin
;
648 unsigned char *cleartext
;
649 unsigned char *final
;
651 size_t cutoff
, cutlen
;
658 return gpg_error (GPG_ERR_INV_SEXP
);
662 return gpg_error (GPG_ERR_INV_SEXP
);
663 if (!smatch (&s
, n
, "protected-private-key"))
664 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
666 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
670 return gpg_error (GPG_ERR_INV_SEXP
);
672 for (infidx
=0; protect_info
[infidx
].algo
673 && !smatch (&s
, n
, protect_info
[infidx
].algo
); infidx
++)
675 if (!protect_info
[infidx
].algo
)
676 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM
);
679 /* See wether we have a protected-at timestamp. */
680 protect_list
= s
; /* Save for later. */
689 return gpg_error (GPG_ERR_INV_SEXP
);
690 if (smatch (&s
, n
, "protected-at"))
694 return gpg_error (GPG_ERR_INV_SEXP
);
696 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
697 memcpy (protected_at
, s
, 15);
698 protected_at
[15] = 0;
709 /* Now find the list with the protected information. Here is an
710 example for such a list:
711 (protected openpgp-s2k3-sha1-aes-cbc
712 ((sha1 <salt> <count>) <Initialization_Vector>)
719 return gpg_error (GPG_ERR_INV_SEXP
);
724 return gpg_error (GPG_ERR_INV_SEXP
);
725 if (smatch (&s
, n
, "protected"))
736 return gpg_error (GPG_ERR_INV_SEXP
);
737 if (!smatch (&s
, n
, "openpgp-s2k3-sha1-" PROT_CIPHER_STRING
"-cbc"))
738 return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION
);
739 if (*s
!= '(' || s
[1] != '(')
740 return gpg_error (GPG_ERR_INV_SEXP
);
744 return gpg_error (GPG_ERR_INV_SEXP
);
745 if (!smatch (&s
, n
, "sha1"))
746 return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION
);
749 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
754 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
755 /* We expect a list close as next, so we can simply use strtoul()
756 here. We might want to check that we only have digits - but this
757 is nothing we should worry about */
759 return gpg_error (GPG_ERR_INV_SEXP
);
760 s2kcount
= strtoul ((const char*)s
, NULL
, 10);
762 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
764 s
++; /* skip list end */
767 if (n
!= 16) /* Wrong blocksize for IV (we support only aes-128). */
768 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
772 return gpg_error (GPG_ERR_INV_SEXP
);
776 return gpg_error (GPG_ERR_INV_SEXP
);
778 rc
= do_decryption (s
, n
,
779 passphrase
, s2ksalt
, s2kcount
,
785 rc
= merge_lists (protectedkey
, prot_begin
-protectedkey
, cleartext
,
786 sha1hash
, &final
, &finallen
, &cutoff
, &cutlen
);
787 /* Albeit cleartext has been allocated in secure memory and thus
788 xfree will wipe it out, we do an extra wipe just in case
789 somethings goes badly wrong. */
790 wipememory (cleartext
, n
);
795 rc
= calculate_mic (final
, sha1hash2
);
796 if (!rc
&& memcmp (sha1hash
, sha1hash2
, 20))
797 rc
= gpg_error (GPG_ERR_CORRUPTED_PROTECTION
);
800 wipememory (final
, finallen
);
804 /* Now remove tha part which is included in the MIC but should not
805 go into the final thing. */
808 memmove (final
+cutoff
, final
+cutoff
+cutlen
, finallen
-cutoff
-cutlen
);
813 *resultlen
= gcry_sexp_canon_len (final
, 0, NULL
, NULL
);
817 /* Check the type of the private key, this is one of the constants:
818 PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the
819 value 0), PRIVATE_KEY_CLEAR for an unprotected private key.
820 PRIVATE_KEY_PROTECTED for an protected private key or
821 PRIVATE_KEY_SHADOWED for a sub key where the secret parts are stored
824 agent_private_key_type (const unsigned char *privatekey
)
826 const unsigned char *s
;
831 return PRIVATE_KEY_UNKNOWN
;
835 return PRIVATE_KEY_UNKNOWN
;
836 if (smatch (&s
, n
, "protected-private-key"))
837 return PRIVATE_KEY_PROTECTED
;
838 if (smatch (&s
, n
, "shadowed-private-key"))
839 return PRIVATE_KEY_SHADOWED
;
840 if (smatch (&s
, n
, "private-key"))
841 return PRIVATE_KEY_CLEAR
;
842 return PRIVATE_KEY_UNKNOWN
;
847 /* Transform a passphrase into a suitable key of length KEYLEN and
848 store this key in the caller provided buffer KEY. The caller must
849 provide an HASHALGO, a valid S2KMODE (see rfc-2440) and depending on
850 that mode an S2KSALT of 8 random bytes and an S2KCOUNT (a suitable
853 Returns an error code on failure. */
855 hash_passphrase (const char *passphrase
, int hashalgo
,
857 const unsigned char *s2ksalt
,
858 unsigned long s2kcount
,
859 unsigned char *key
, size_t keylen
)
865 int pwlen
= strlen (passphrase
);
867 if ( (s2kmode
!= 0 && s2kmode
!= 1 && s2kmode
!= 3)
868 || !hashalgo
|| !keylen
|| !key
|| !passphrase
)
869 return gpg_error (GPG_ERR_INV_VALUE
);
870 if ((s2kmode
== 1 ||s2kmode
== 3) && !s2ksalt
)
871 return gpg_error (GPG_ERR_INV_VALUE
);
873 rc
= gcry_md_open (&md
, hashalgo
, GCRY_MD_FLAG_SECURE
);
877 for (pass
=0; used
< keylen
; pass
++)
882 for (i
=0; i
< pass
; i
++) /* preset the hash context */
883 gcry_md_putc (md
, 0);
886 if (s2kmode
== 1 || s2kmode
== 3)
888 int len2
= pwlen
+ 8;
889 unsigned long count
= len2
;
893 count
= (16ul + (s2kcount
& 15)) << ((s2kcount
>> 4) + 6);
900 gcry_md_write (md
, s2ksalt
, 8);
901 gcry_md_write (md
, passphrase
, pwlen
);
905 gcry_md_write (md
, s2ksalt
, count
);
908 gcry_md_write (md
, s2ksalt
, 8);
910 gcry_md_write (md
, passphrase
, count
);
914 gcry_md_write (md
, passphrase
, pwlen
);
917 i
= gcry_md_get_algo_dlen (hashalgo
);
918 if (i
> keylen
- used
)
920 memcpy (key
+used
, gcry_md_read (md
, hashalgo
), i
);
930 /* Create an canonical encoded S-expression with the shadow info from
931 a card's SERIALNO and the IDSTRING. */
933 make_shadow_info (const char *serialno
, const char *idstring
)
940 for (s
=serialno
, n
=0; *s
&& s
[1]; s
+= 2)
943 info
= p
= xtrymalloc (1 + sizeof numbuf
+ n
944 + sizeof numbuf
+ strlen (idstring
) + 1 + 1);
948 p
= stpcpy (p
, smklen (numbuf
, sizeof numbuf
, n
, NULL
));
949 for (s
=serialno
; *s
&& s
[1]; s
+= 2)
950 *(unsigned char *)p
++ = xtoi_2 (s
);
951 p
= stpcpy (p
, smklen (numbuf
, sizeof numbuf
, strlen (idstring
), NULL
));
952 p
= stpcpy (p
, idstring
);
955 return (unsigned char *)info
;
960 /* Create a shadow key from a public key. We use the shadow protocol
961 "ti-v1" and insert the S-expressionn SHADOW_INFO. The resulting
962 S-expression is returned in an allocated buffer RESULT will point
963 to. The input parameters are expected to be valid canonicalized
966 agent_shadow_key (const unsigned char *pubkey
,
967 const unsigned char *shadow_info
,
968 unsigned char **result
)
970 const unsigned char *s
;
971 const unsigned char *point
;
975 size_t pubkey_len
= gcry_sexp_canon_len (pubkey
, 0, NULL
,NULL
);
976 size_t shadow_info_len
= gcry_sexp_canon_len (shadow_info
, 0, NULL
,NULL
);
978 if (!pubkey_len
|| !shadow_info_len
)
979 return gpg_error (GPG_ERR_INV_VALUE
);
982 return gpg_error (GPG_ERR_INV_SEXP
);
987 return gpg_error (GPG_ERR_INV_SEXP
);
988 if (!smatch (&s
, n
, "public-key"))
989 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
991 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
996 return gpg_error (GPG_ERR_INV_SEXP
);
997 s
+= n
; /* skip over the algorithm name */
1002 return gpg_error (GPG_ERR_INV_SEXP
);
1007 return gpg_error (GPG_ERR_INV_SEXP
);
1011 return gpg_error (GPG_ERR_INV_SEXP
);
1012 s
+=n
; /* skip value */
1014 return gpg_error (GPG_ERR_INV_SEXP
);
1018 point
= s
; /* insert right before the point */
1021 assert (depth
== 1);
1023 /* Calculate required length by taking in account: the "shadowed-"
1024 prefix, the "shadowed", "t1-v1" as well as some parenthesis */
1025 n
= 12 + pubkey_len
+ 1 + 3+8 + 2+5 + shadow_info_len
+ 1;
1026 *result
= xtrymalloc (n
);
1029 return out_of_core ();
1030 p
= stpcpy (p
, "(20:shadowed-private-key");
1031 /* (10:public-key ...)*/
1032 memcpy (p
, pubkey
+14, point
- (pubkey
+14));
1033 p
+= point
- (pubkey
+14);
1034 p
= stpcpy (p
, "(8:shadowed5:t1-v1");
1035 memcpy (p
, shadow_info
, shadow_info_len
);
1036 p
+= shadow_info_len
;
1038 memcpy (p
, point
, pubkey_len
- (point
- pubkey
));
1039 p
+= pubkey_len
- (point
- pubkey
);
1044 /* Parse a canonical encoded shadowed key and return a pointer to the
1045 inner list with the shadow_info */
1047 agent_get_shadow_info (const unsigned char *shadowkey
,
1048 unsigned char const **shadow_info
)
1050 const unsigned char *s
;
1056 return gpg_error (GPG_ERR_INV_SEXP
);
1061 return gpg_error (GPG_ERR_INV_SEXP
);
1062 if (!smatch (&s
, n
, "shadowed-private-key"))
1063 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
1065 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
1070 return gpg_error (GPG_ERR_INV_SEXP
);
1071 s
+= n
; /* skip over the algorithm name */
1076 return gpg_error (GPG_ERR_UNKNOWN_SEXP
);
1078 return gpg_error (GPG_ERR_INV_SEXP
);
1083 return gpg_error (GPG_ERR_INV_SEXP
);
1084 if (smatch (&s
, n
, "shadowed"))
1089 return gpg_error (GPG_ERR_INV_SEXP
);
1090 s
+=n
; /* skip value */
1092 return gpg_error (GPG_ERR_INV_SEXP
);
1096 /* Found the shadowed list, S points to the protocol */
1099 return gpg_error (GPG_ERR_INV_SEXP
);
1100 if (smatch (&s
, n
, "t1-v1"))
1103 return gpg_error (GPG_ERR_INV_SEXP
);
1107 return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL
);
1112 /* Parse the canonical encoded SHADOW_INFO S-expression. On success
1113 the hex encoded serial number is returned as a malloced strings at
1114 R_HEXSN and the Id string as a malloced string at R_IDSTR. On
1115 error an error code is returned and NULL is stored at the result
1116 parameters addresses. If the serial number or the ID string is not
1117 required, NULL may be passed for them. */
1119 parse_shadow_info (const unsigned char *shadow_info
,
1120 char **r_hexsn
, char **r_idstr
)
1122 const unsigned char *s
;
1132 return gpg_error (GPG_ERR_INV_SEXP
);
1136 return gpg_error (GPG_ERR_INV_SEXP
);
1140 *r_hexsn
= bin2hex (s
, n
, NULL
);
1142 return gpg_error_from_syserror ();
1154 return gpg_error (GPG_ERR_INV_SEXP
);
1159 *r_idstr
= xtrymalloc (n
+1);
1167 return gpg_error_from_syserror ();
1169 memcpy (*r_idstr
, s
, n
);