gpg: Change OID of Ed25519 and add Brainpool oids.
[gnupg.git] / common / ssh-utils.c
1 /* ssh-utils.c - Secure Shell helper functions
2  * Copyright (C) 2011 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * This file is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, see <http://www.gnu.org/licenses/>.
28  */
29
30 #include <config.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <ctype.h>
34 #include <assert.h>
35
36 #include "util.h"
37 #include "ssh-utils.h"
38
39
40
41 /* Return the Secure Shell type fingerprint for KEY.  The length of
42    the fingerprint is returned at R_LEN and the fingerprint itself at
43    R_FPR.  In case of a error code is returned and NULL stored at
44    R_FPR.  */
45 static gpg_error_t
46 get_fingerprint (gcry_sexp_t key, void **r_fpr, size_t *r_len, int as_string)
47 {
48   gpg_error_t err;
49   gcry_sexp_t list = NULL;
50   gcry_sexp_t l2 = NULL;
51   const char *s;
52   char *name = NULL;
53   int idx;
54   const char *elems;
55   gcry_md_hd_t md = NULL;
56
57   *r_fpr = NULL;
58   *r_len = 0;
59
60   /* Check that the first element is valid. */
61   list = gcry_sexp_find_token (key, "public-key", 0);
62   if (!list)
63     list = gcry_sexp_find_token (key, "private-key", 0);
64   if (!list)
65     list = gcry_sexp_find_token (key, "protected-private-key", 0);
66   if (!list)
67     list = gcry_sexp_find_token (key, "shadowed-private-key", 0);
68   if (!list)
69     {
70       err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_SEXP);
71       goto leave;
72     }
73
74   l2 = gcry_sexp_cadr (list);
75   gcry_sexp_release (list);
76   list = l2;
77   l2 = NULL;
78
79   name = gcry_sexp_nth_string (list, 0);
80   if (!name)
81     {
82       err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
83       goto leave;
84     }
85
86   err = gcry_md_open (&md, GCRY_MD_MD5, 0);
87   if (err)
88     goto leave;
89
90   switch (gcry_pk_map_name (name))
91     {
92     case GCRY_PK_RSA:
93       elems = "en";
94       gcry_md_write (md, "\0\0\0\x07ssh-rsa", 11);
95       break;
96     case GCRY_PK_DSA:
97       elems = "pqgy";
98       gcry_md_write (md, "\0\0\0\x07ssh-dss", 11);
99       break;
100     case GCRY_PK_ECDSA:
101       /* We only support the 3 standard curves for now.  It is just a
102          quick hack.  */
103       elems = "q";
104       gcry_md_write (md, "\0\0\0\x13" "ecdsa-sha2-nistp", 20);
105       l2 = gcry_sexp_find_token (list, "curve", 0);
106       if (!l2)
107         elems = "";
108       else
109         {
110           gcry_free (name);
111           name = gcry_sexp_nth_string (l2, 1);
112           gcry_sexp_release (l2);
113           l2 = NULL;
114           if (!name)
115             elems = "";
116           else if (!strcmp (name, "NIST P-256") || !strcmp (name, "nistp256"))
117             gcry_md_write (md, "256\0\0\0\x08nistp256", 15);
118           else if (!strcmp (name, "NIST P-384") || !strcmp (name, "nistp384"))
119             gcry_md_write (md, "384\0\0\0\x08nistp521", 15);
120           else if (!strcmp (name, "NIST P-521") || !strcmp (name, "nistp521"))
121             gcry_md_write (md, "521\0\0\0\x08nistp521", 15);
122           else
123             elems = "";
124         }
125       if (!*elems)
126         err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_CURVE);
127       break;
128     default:
129       elems = "";
130       err = gpg_err_make (default_errsource, GPG_ERR_PUBKEY_ALGO);
131       break;
132     }
133   if (err)
134     goto leave;
135
136   for (idx = 0, s = elems; *s; s++, idx++)
137     {
138       gcry_mpi_t a;
139       unsigned char *buf;
140       size_t buflen;
141
142       l2 = gcry_sexp_find_token (list, s, 1);
143       if (!l2)
144         {
145           err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
146           goto leave;
147         }
148       a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
149       gcry_sexp_release (l2);
150       l2 = NULL;
151       if (!a)
152         {
153           err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
154           goto leave;
155         }
156
157       err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a);
158       gcry_mpi_release (a);
159       if (err)
160         goto leave;
161       gcry_md_write (md, buf, buflen);
162       gcry_free (buf);
163     }
164
165   *r_fpr = gcry_malloc (as_string? 61:20);
166   if (!*r_fpr)
167     {
168       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
169       goto leave;
170     }
171
172   if (as_string)
173     {
174       bin2hexcolon (gcry_md_read (md, GCRY_MD_MD5), 16, *r_fpr);
175       *r_len = 3*16+1;
176       strlwr (*r_fpr);
177     }
178   else
179     {
180       memcpy (*r_fpr, gcry_md_read (md, GCRY_MD_MD5), 16);
181       *r_len = 16;
182     }
183   err = 0;
184
185  leave:
186   gcry_free (name);
187   gcry_sexp_release (l2);
188   gcry_md_close (md);
189   gcry_sexp_release (list);
190   return err;
191 }
192
193 /* Return the Secure Shell type fingerprint for KEY.  The length of
194    the fingerprint is returned at R_LEN and the fingerprint itself at
195    R_FPR.  In case of an error an error code is returned and NULL
196    stored at R_FPR.  */
197 gpg_error_t
198 ssh_get_fingerprint (gcry_sexp_t key, void **r_fpr, size_t *r_len)
199 {
200   return get_fingerprint (key, r_fpr, r_len, 0);
201 }
202
203
204 /* Return the Secure Shell type fingerprint for KEY as a string.  The
205    fingerprint is mallcoed and stored at R_FPRSTR.  In case of an
206    error an error code is returned and NULL stored at R_FPRSTR.  */
207 gpg_error_t
208 ssh_get_fingerprint_string (gcry_sexp_t key, char **r_fprstr)
209 {
210   gpg_error_t err;
211   size_t dummy;
212   void *string;
213
214   err = get_fingerprint (key, &string, &dummy, 1);
215   *r_fprstr = string;
216   return err;
217 }