blob: bbe027b668557740feeb2ccff26db573525fba20 [file] [log] [blame]
djm@openbsd.org9ce86c92015-01-28 22:36:00 +00001/* $OpenBSD: key.c,v 1.127 2015/01/28 22:36:00 djm Exp $ */
Damien Miller450a7a12000-03-26 13:04:51 +10002/*
Damien Miller86687062014-07-02 15:28:02 +10003 * placed in the public domain
Damien Miller450a7a12000-03-26 13:04:51 +10004 */
Damien Millerd7834352006-08-05 12:39:39 +10005
Damien Miller450a7a12000-03-26 13:04:51 +10006#include "includes.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +00007
Damien Millerd7834352006-08-05 12:39:39 +10008#include <sys/types.h>
Damien Miller86687062014-07-02 15:28:02 +10009#include <errno.h>
Damien Millerded319c2006-09-01 15:38:36 +100010#include <stdarg.h>
Damien Millera7a73ee2006-08-05 11:37:59 +100011#include <stdio.h>
deraadt@openbsd.org087266e2015-01-20 23:14:00 +000012#include <limits.h>
Damien Millere3476ed2006-07-24 14:13:33 +100013
Damien Miller86687062014-07-02 15:28:02 +100014#define SSH_KEY_NO_DEFINE
Damien Miller450a7a12000-03-26 13:04:51 +100015#include "key.h"
Damien Miller86687062014-07-02 15:28:02 +100016
17#include "compat.h"
18#include "sshkey.h"
19#include "ssherr.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000020#include "log.h"
Damien Miller86687062014-07-02 15:28:02 +100021#include "authfile.h"
Ben Lindstrom836f0e92002-06-23 21:21:30 +000022
Damien Miller0a80ca12010-02-27 07:55:05 +110023void
24key_add_private(Key *k)
Damien Miller0bc1bd82000-11-13 22:57:25 +110025{
Damien Miller86687062014-07-02 15:28:02 +100026 int r;
27
28 if ((r = sshkey_add_private(k)) != 0)
29 fatal("%s: %s", __func__, ssh_err(r));
Damien Miller0a80ca12010-02-27 07:55:05 +110030}
31
32Key *
33key_new_private(int type)
34{
Damien Miller86687062014-07-02 15:28:02 +100035 Key *ret = NULL;
Damien Miller0a80ca12010-02-27 07:55:05 +110036
Damien Miller86687062014-07-02 15:28:02 +100037 if ((ret = sshkey_new_private(type)) == NULL)
38 fatal("%s: failed", __func__);
39 return ret;
Damien Miller0a80ca12010-02-27 07:55:05 +110040}
41
Damien Miller0bc1bd82000-11-13 22:57:25 +110042int
Damien Millereba71ba2000-04-29 23:57:08 +100043key_read(Key *ret, char **cpp)
Damien Miller450a7a12000-03-26 13:04:51 +100044{
Damien Miller86687062014-07-02 15:28:02 +100045 return sshkey_read(ret, cpp) == 0 ? 1 : -1;
Damien Miller450a7a12000-03-26 13:04:51 +100046}
Ben Lindstrom836f0e92002-06-23 21:21:30 +000047
Damien Miller450a7a12000-03-26 13:04:51 +100048int
Damien Millerf58b58c2003-11-17 21:18:23 +110049key_write(const Key *key, FILE *f)
Damien Miller450a7a12000-03-26 13:04:51 +100050{
Damien Miller86687062014-07-02 15:28:02 +100051 return sshkey_write(key, f) == 0 ? 1 : 0;
Damien Miller450a7a12000-03-26 13:04:51 +100052}
Ben Lindstrom836f0e92002-06-23 21:21:30 +000053
Damien Miller0bc1bd82000-11-13 22:57:25 +110054Key *
Ben Lindstrom46c16222000-12-22 01:43:59 +000055key_generate(int type, u_int bits)
Damien Miller0bc1bd82000-11-13 22:57:25 +110056{
Damien Miller86687062014-07-02 15:28:02 +100057 int r;
58 Key *ret = NULL;
59
60 if ((r = sshkey_generate(type, bits, &ret)) != 0)
61 fatal("%s: %s", __func__, ssh_err(r));
62 return ret;
Damien Miller0bc1bd82000-11-13 22:57:25 +110063}
64
Damien Miller0a80ca12010-02-27 07:55:05 +110065void
Damien Miller86687062014-07-02 15:28:02 +100066key_cert_copy(const Key *from_key, Key *to_key)
Damien Miller0a80ca12010-02-27 07:55:05 +110067{
Damien Miller86687062014-07-02 15:28:02 +100068 int r;
Damien Miller0a80ca12010-02-27 07:55:05 +110069
Damien Miller86687062014-07-02 15:28:02 +100070 if ((r = sshkey_cert_copy(from_key, to_key)) != 0)
71 fatal("%s: %s", __func__, ssh_err(r));
Damien Miller0a80ca12010-02-27 07:55:05 +110072}
73
Damien Miller0bc1bd82000-11-13 22:57:25 +110074Key *
Damien Millerf58b58c2003-11-17 21:18:23 +110075key_from_private(const Key *k)
Damien Miller0bc1bd82000-11-13 22:57:25 +110076{
Damien Miller86687062014-07-02 15:28:02 +100077 int r;
78 Key *ret = NULL;
Damien Miller0bc1bd82000-11-13 22:57:25 +110079
Damien Miller86687062014-07-02 15:28:02 +100080 if ((r = sshkey_from_private(k, &ret)) != 0)
81 fatal("%s: %s", __func__, ssh_err(r));
Damien Miller0a80ca12010-02-27 07:55:05 +110082 return ret;
83}
84
Damien Miller86687062014-07-02 15:28:02 +100085static void
86fatal_on_fatal_errors(int r, const char *func, int extra_fatal)
Damien Miller0bc1bd82000-11-13 22:57:25 +110087{
Damien Miller86687062014-07-02 15:28:02 +100088 if (r == SSH_ERR_INTERNAL_ERROR ||
89 r == SSH_ERR_ALLOC_FAIL ||
90 (extra_fatal != 0 && r == extra_fatal))
91 fatal("%s: %s", func, ssh_err(r));
Damien Miller0bc1bd82000-11-13 22:57:25 +110092}
93
Damien Miller4a3a9d42013-10-30 22:19:47 +110094Key *
95key_from_blob(const u_char *blob, u_int blen)
96{
Damien Miller86687062014-07-02 15:28:02 +100097 int r;
98 Key *ret = NULL;
Damien Miller4a3a9d42013-10-30 22:19:47 +110099
Damien Miller86687062014-07-02 15:28:02 +1000100 if ((r = sshkey_from_blob(blob, blen, &ret)) != 0) {
101 fatal_on_fatal_errors(r, __func__, 0);
102 error("%s: %s", __func__, ssh_err(r));
103 return NULL;
Damien Miller0bc1bd82000-11-13 22:57:25 +1100104 }
Damien Miller86687062014-07-02 15:28:02 +1000105 return ret;
Damien Miller0bc1bd82000-11-13 22:57:25 +1100106}
107
108int
Damien Millerf3747bf2013-01-18 11:44:04 +1100109key_to_blob(const Key *key, u_char **blobp, u_int *lenp)
110{
Damien Miller86687062014-07-02 15:28:02 +1000111 u_char *blob;
112 size_t blen;
113 int r;
114
115 if (blobp != NULL)
116 *blobp = NULL;
117 if (lenp != NULL)
118 *lenp = 0;
119 if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
120 fatal_on_fatal_errors(r, __func__, 0);
121 error("%s: %s", __func__, ssh_err(r));
122 return 0;
123 }
124 if (blen > INT_MAX)
125 fatal("%s: giant len %zu", __func__, blen);
126 if (blobp != NULL)
127 *blobp = blob;
128 if (lenp != NULL)
129 *lenp = blen;
130 return blen;
Damien Millerf3747bf2013-01-18 11:44:04 +1100131}
132
133int
Damien Miller86687062014-07-02 15:28:02 +1000134key_sign(const Key *key, u_char **sigp, u_int *lenp,
Damien Millerf58b58c2003-11-17 21:18:23 +1100135 const u_char *data, u_int datalen)
Damien Miller0bc1bd82000-11-13 22:57:25 +1100136{
Damien Miller86687062014-07-02 15:28:02 +1000137 int r;
138 u_char *sig;
139 size_t siglen;
140
141 if (sigp != NULL)
142 *sigp = NULL;
143 if (lenp != NULL)
144 *lenp = 0;
145 if ((r = sshkey_sign(key, &sig, &siglen,
146 data, datalen, datafellows)) != 0) {
147 fatal_on_fatal_errors(r, __func__, 0);
148 error("%s: %s", __func__, ssh_err(r));
Damien Miller0bc1bd82000-11-13 22:57:25 +1100149 return -1;
Damien Miller0bc1bd82000-11-13 22:57:25 +1100150 }
Damien Miller86687062014-07-02 15:28:02 +1000151 if (siglen > INT_MAX)
152 fatal("%s: giant len %zu", __func__, siglen);
153 if (sigp != NULL)
154 *sigp = sig;
155 if (lenp != NULL)
156 *lenp = siglen;
Damien Miller5be9d9e2013-12-07 11:24:01 +1100157 return 0;
Damien Miller0a80ca12010-02-27 07:55:05 +1100158}
159
Damien Miller86687062014-07-02 15:28:02 +1000160int
161key_verify(const Key *key, const u_char *signature, u_int signaturelen,
162 const u_char *data, u_int datalen)
163{
164 int r;
165
166 if ((r = sshkey_verify(key, signature, signaturelen,
167 data, datalen, datafellows)) != 0) {
168 fatal_on_fatal_errors(r, __func__, 0);
169 error("%s: %s", __func__, ssh_err(r));
170 return r == SSH_ERR_SIGNATURE_INVALID ? 0 : -1;
171 }
172 return 1;
173}
174
175Key *
176key_demote(const Key *k)
177{
178 int r;
179 Key *ret = NULL;
180
181 if ((r = sshkey_demote(k, &ret)) != 0)
182 fatal("%s: %s", __func__, ssh_err(r));
183 return ret;
184}
185
186int
187key_to_certified(Key *k, int legacy)
188{
189 int r;
190
191 if ((r = sshkey_to_certified(k, legacy)) != 0) {
192 fatal_on_fatal_errors(r, __func__, 0);
193 error("%s: %s", __func__, ssh_err(r));
194 return -1;
195 }
196 return 0;
197}
198
199int
200key_drop_cert(Key *k)
201{
202 int r;
203
204 if ((r = sshkey_drop_cert(k)) != 0) {
205 fatal_on_fatal_errors(r, __func__, 0);
206 error("%s: %s", __func__, ssh_err(r));
207 return -1;
208 }
209 return 0;
210}
211
Damien Miller0a80ca12010-02-27 07:55:05 +1100212int
213key_certify(Key *k, Key *ca)
214{
Damien Miller86687062014-07-02 15:28:02 +1000215 int r;
Damien Miller0a80ca12010-02-27 07:55:05 +1100216
Damien Miller86687062014-07-02 15:28:02 +1000217 if ((r = sshkey_certify(k, ca)) != 0) {
218 fatal_on_fatal_errors(r, __func__, 0);
219 error("%s: %s", __func__, ssh_err(r));
Damien Miller0a80ca12010-02-27 07:55:05 +1100220 return -1;
221 }
Damien Miller0a80ca12010-02-27 07:55:05 +1100222 return 0;
223}
224
225int
226key_cert_check_authority(const Key *k, int want_host, int require_principal,
227 const char *name, const char **reason)
228{
Damien Miller86687062014-07-02 15:28:02 +1000229 int r;
Damien Miller0a80ca12010-02-27 07:55:05 +1100230
Damien Miller86687062014-07-02 15:28:02 +1000231 if ((r = sshkey_cert_check_authority(k, want_host, require_principal,
232 name, reason)) != 0) {
233 fatal_on_fatal_errors(r, __func__, 0);
234 error("%s: %s", __func__, ssh_err(r));
Damien Miller0a80ca12010-02-27 07:55:05 +1100235 return -1;
236 }
Damien Miller86687062014-07-02 15:28:02 +1000237 return 0;
238}
239
Darren Tuckerd1a04212014-07-19 07:23:55 +1000240#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
Damien Miller86687062014-07-02 15:28:02 +1000241int
242key_ec_validate_public(const EC_GROUP *group, const EC_POINT *public)
243{
244 int r;
245
246 if ((r = sshkey_ec_validate_public(group, public)) != 0) {
247 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
248 error("%s: %s", __func__, ssh_err(r));
Damien Miller0a80ca12010-02-27 07:55:05 +1100249 return -1;
250 }
Damien Miller0a80ca12010-02-27 07:55:05 +1100251 return 0;
252}
Damien Miller4e270b02010-04-16 15:56:21 +1000253
254int
Damien Millereb8b60e2010-08-31 22:41:14 +1000255key_ec_validate_private(const EC_KEY *key)
256{
Damien Miller86687062014-07-02 15:28:02 +1000257 int r;
Damien Millereb8b60e2010-08-31 22:41:14 +1000258
Damien Miller86687062014-07-02 15:28:02 +1000259 if ((r = sshkey_ec_validate_private(key)) != 0) {
260 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
261 error("%s: %s", __func__, ssh_err(r));
262 return -1;
Damien Millereb8b60e2010-08-31 22:41:14 +1000263 }
Damien Miller86687062014-07-02 15:28:02 +1000264 return 0;
Damien Millereb8b60e2010-08-31 22:41:14 +1000265}
Damien Miller86687062014-07-02 15:28:02 +1000266#endif /* WITH_OPENSSL */
Damien Millereb8b60e2010-08-31 22:41:14 +1000267
268void
Damien Miller86687062014-07-02 15:28:02 +1000269key_private_serialize(const Key *key, struct sshbuf *b)
Damien Millereb8b60e2010-08-31 22:41:14 +1000270{
Damien Miller86687062014-07-02 15:28:02 +1000271 int r;
Damien Millereb8b60e2010-08-31 22:41:14 +1000272
Damien Miller86687062014-07-02 15:28:02 +1000273 if ((r = sshkey_private_serialize(key, b)) != 0)
274 fatal("%s: %s", __func__, ssh_err(r));
Damien Millerf0e90602013-12-07 10:40:26 +1100275}
276
277Key *
Damien Miller86687062014-07-02 15:28:02 +1000278key_private_deserialize(struct sshbuf *blob)
Damien Millerf0e90602013-12-07 10:40:26 +1100279{
Damien Miller86687062014-07-02 15:28:02 +1000280 int r;
281 Key *ret = NULL;
Damien Millerf0e90602013-12-07 10:40:26 +1100282
Damien Miller86687062014-07-02 15:28:02 +1000283 if ((r = sshkey_private_deserialize(blob, &ret)) != 0) {
284 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
285 error("%s: %s", __func__, ssh_err(r));
Damien Millerf0e90602013-12-07 10:40:26 +1100286 return NULL;
287 }
Damien Miller86687062014-07-02 15:28:02 +1000288 return ret;
289}
Damien Millerf0e90602013-12-07 10:40:26 +1100290
Damien Miller86687062014-07-02 15:28:02 +1000291/* authfile.c */
292
293int
294key_save_private(Key *key, const char *filename, const char *passphrase,
295 const char *comment, int force_new_format, const char *new_format_cipher,
296 int new_format_rounds)
297{
298 int r;
299
300 if ((r = sshkey_save_private(key, filename, passphrase, comment,
301 force_new_format, new_format_cipher, new_format_rounds)) != 0) {
302 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
303 error("%s: %s", __func__, ssh_err(r));
304 return 0;
Damien Millerf0e90602013-12-07 10:40:26 +1100305 }
Damien Miller86687062014-07-02 15:28:02 +1000306 return 1;
307}
308
309int
310key_load_file(int fd, const char *filename, struct sshbuf *blob)
311{
312 int r;
313
djm@openbsd.org1195f4c2015-01-08 10:14:08 +0000314 if ((r = sshkey_load_file(fd, blob)) != 0) {
Damien Miller86687062014-07-02 15:28:02 +1000315 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
316 error("%s: %s", __func__, ssh_err(r));
317 return 0;
318 }
319 return 1;
320}
321
322Key *
323key_load_cert(const char *filename)
324{
325 int r;
326 Key *ret = NULL;
327
328 if ((r = sshkey_load_cert(filename, &ret)) != 0) {
329 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
Damien Millerd0bb9502014-07-09 13:07:28 +1000330 /* Old authfile.c ignored all file errors. */
331 if (r == SSH_ERR_SYSTEM_ERROR)
Damien Miller86687062014-07-02 15:28:02 +1000332 debug("%s: %s", __func__, ssh_err(r));
333 else
334 error("%s: %s", __func__, ssh_err(r));
335 return NULL;
336 }
337 return ret;
338
339}
340
341Key *
342key_load_public(const char *filename, char **commentp)
343{
344 int r;
345 Key *ret = NULL;
346
347 if ((r = sshkey_load_public(filename, &ret, commentp)) != 0) {
348 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
Damien Millerd0bb9502014-07-09 13:07:28 +1000349 /* Old authfile.c ignored all file errors. */
350 if (r == SSH_ERR_SYSTEM_ERROR)
Damien Miller86687062014-07-02 15:28:02 +1000351 debug("%s: %s", __func__, ssh_err(r));
352 else
353 error("%s: %s", __func__, ssh_err(r));
354 return NULL;
355 }
356 return ret;
357}
358
359Key *
360key_load_private(const char *path, const char *passphrase,
361 char **commentp)
362{
363 int r;
364 Key *ret = NULL;
365
366 if ((r = sshkey_load_private(path, passphrase, &ret, commentp)) != 0) {
367 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
Damien Millerd0bb9502014-07-09 13:07:28 +1000368 /* Old authfile.c ignored all file errors. */
Damien Millerdad9a4a2014-07-18 15:03:49 +1000369 if (r == SSH_ERR_SYSTEM_ERROR ||
370 r == SSH_ERR_KEY_WRONG_PASSPHRASE)
Damien Miller86687062014-07-02 15:28:02 +1000371 debug("%s: %s", __func__, ssh_err(r));
372 else
373 error("%s: %s", __func__, ssh_err(r));
374 return NULL;
375 }
376 return ret;
377}
378
379Key *
380key_load_private_cert(int type, const char *filename, const char *passphrase,
381 int *perm_ok)
382{
383 int r;
384 Key *ret = NULL;
385
386 if ((r = sshkey_load_private_cert(type, filename, passphrase,
387 &ret, perm_ok)) != 0) {
388 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
Damien Millerd0bb9502014-07-09 13:07:28 +1000389 /* Old authfile.c ignored all file errors. */
Damien Millerdad9a4a2014-07-18 15:03:49 +1000390 if (r == SSH_ERR_SYSTEM_ERROR ||
391 r == SSH_ERR_KEY_WRONG_PASSPHRASE)
Damien Miller86687062014-07-02 15:28:02 +1000392 debug("%s: %s", __func__, ssh_err(r));
393 else
394 error("%s: %s", __func__, ssh_err(r));
395 return NULL;
396 }
397 return ret;
398}
399
400Key *
401key_load_private_type(int type, const char *filename, const char *passphrase,
402 char **commentp, int *perm_ok)
403{
404 int r;
405 Key *ret = NULL;
406
407 if ((r = sshkey_load_private_type(type, filename, passphrase,
408 &ret, commentp, perm_ok)) != 0) {
409 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
Damien Millerd0bb9502014-07-09 13:07:28 +1000410 /* Old authfile.c ignored all file errors. */
411 if (r == SSH_ERR_SYSTEM_ERROR ||
Damien Miller86687062014-07-02 15:28:02 +1000412 (r == SSH_ERR_KEY_WRONG_PASSPHRASE))
413 debug("%s: %s", __func__, ssh_err(r));
414 else
415 error("%s: %s", __func__, ssh_err(r));
416 return NULL;
417 }
418 return ret;
419}
420
Damien Miller86687062014-07-02 15:28:02 +1000421int
422key_perm_ok(int fd, const char *filename)
423{
424 return sshkey_perm_ok(fd, filename) == 0 ? 1 : 0;
425}
426