diff options
author | Damien Miller <djm@mindrot.org> | 2014-07-02 15:28:02 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2014-07-02 15:28:02 +1000 |
commit | 8668706d0f52654fe64c0ca41a96113aeab8d2b8 (patch) | |
tree | 73e78e1ea3d39206e39870bbe0af17d6c430fb51 | |
parent | 2cd7929250cf9e9f658d70dcd452f529ba08c942 (diff) |
- djm@cvs.openbsd.org 2014/06/24 01:13:21
[Makefile.in auth-bsdauth.c auth-chall.c auth-options.c auth-rsa.c
[auth2-none.c auth2-pubkey.c authfile.c authfile.h cipher-3des1.c
[cipher-chachapoly.c cipher-chachapoly.h cipher.c cipher.h
[digest-libc.c digest-openssl.c digest.h dns.c entropy.c hmac.h
[hostfile.c key.c key.h krl.c monitor.c packet.c rsa.c rsa.h
[ssh-add.c ssh-agent.c ssh-dss.c ssh-ecdsa.c ssh-ed25519.c
[ssh-keygen.c ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c
[ssh-rsa.c sshbuf-misc.c sshbuf.h sshconnect.c sshconnect1.c
[sshconnect2.c sshd.c sshkey.c sshkey.h
[openbsd-compat/openssl-compat.c openbsd-compat/openssl-compat.h]
New key API: refactor key-related functions to be more library-like,
existing API is offered as a set of wrappers.
with and ok markus@
Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew
Dempsky and Ron Bowes for a detailed review a few months ago.
NB. This commit also removes portable OpenSSH support for OpenSSL
<0.9.8e.
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | Makefile.in | 5 | ||||
-rw-r--r-- | auth-bsdauth.c | 4 | ||||
-rw-r--r-- | auth-chall.c | 5 | ||||
-rw-r--r-- | auth-options.c | 14 | ||||
-rw-r--r-- | auth-rsa.c | 5 | ||||
-rw-r--r-- | auth2-none.c | 5 | ||||
-rw-r--r-- | auth2-pubkey.c | 6 | ||||
-rw-r--r-- | authfile.c | 1421 | ||||
-rw-r--r-- | authfile.h | 63 | ||||
-rw-r--r-- | cipher-3des1.c | 55 | ||||
-rw-r--r-- | cipher-chachapoly.c | 25 | ||||
-rw-r--r-- | cipher-chachapoly.h | 4 | ||||
-rw-r--r-- | cipher.c | 363 | ||||
-rw-r--r-- | cipher.h | 57 | ||||
-rw-r--r-- | digest-libc.c | 27 | ||||
-rw-r--r-- | digest-openssl.c | 36 | ||||
-rw-r--r-- | digest.h | 7 | ||||
-rw-r--r-- | dns.c | 4 | ||||
-rw-r--r-- | entropy.c | 2 | ||||
-rw-r--r-- | hmac.h | 5 | ||||
-rw-r--r-- | hostfile.c | 3 | ||||
-rw-r--r-- | key.c | 2803 | ||||
-rw-r--r-- | key.h | 187 | ||||
-rw-r--r-- | krl.c | 8 | ||||
-rw-r--r-- | monitor.c | 5 | ||||
-rw-r--r-- | openbsd-compat/openssl-compat.c | 141 | ||||
-rw-r--r-- | openbsd-compat/openssl-compat.h | 118 | ||||
-rw-r--r-- | packet.c | 38 | ||||
-rw-r--r-- | rsa.c | 113 | ||||
-rw-r--r-- | rsa.h | 6 | ||||
-rw-r--r-- | ssh-add.c | 24 | ||||
-rw-r--r-- | ssh-agent.c | 24 | ||||
-rw-r--r-- | ssh-dss.c | 237 | ||||
-rw-r--r-- | ssh-ecdsa.c | 232 | ||||
-rw-r--r-- | ssh-ed25519.c | 183 | ||||
-rw-r--r-- | ssh-keygen.c | 20 | ||||
-rw-r--r-- | ssh-pkcs11-client.c | 4 | ||||
-rw-r--r-- | ssh-pkcs11-helper.c | 8 | ||||
-rw-r--r-- | ssh-pkcs11.c | 4 | ||||
-rw-r--r-- | ssh-rsa.c | 260 | ||||
-rw-r--r-- | sshbuf-misc.c | 16 | ||||
-rw-r--r-- | sshbuf.h | 7 | ||||
-rw-r--r-- | sshconnect.c | 4 | ||||
-rw-r--r-- | sshconnect1.c | 18 | ||||
-rw-r--r-- | sshconnect2.c | 8 | ||||
-rw-r--r-- | sshd.c | 16 | ||||
-rw-r--r-- | sshkey.c | 3843 | ||||
-rw-r--r-- | sshkey.h | 222 |
49 files changed, 5812 insertions, 4873 deletions
@@ -24,6 +24,26 @@ | |||
24 | 24 | ||
25 | Readers of a broken KRL caused by this bug will fail closed, so no | 25 | Readers of a broken KRL caused by this bug will fail closed, so no |
26 | should-have-been-revoked key will be accepted. | 26 | should-have-been-revoked key will be accepted. |
27 | - djm@cvs.openbsd.org 2014/06/24 01:13:21 | ||
28 | [Makefile.in auth-bsdauth.c auth-chall.c auth-options.c auth-rsa.c | ||
29 | [auth2-none.c auth2-pubkey.c authfile.c authfile.h cipher-3des1.c | ||
30 | [cipher-chachapoly.c cipher-chachapoly.h cipher.c cipher.h | ||
31 | [digest-libc.c digest-openssl.c digest.h dns.c entropy.c hmac.h | ||
32 | [hostfile.c key.c key.h krl.c monitor.c packet.c rsa.c rsa.h | ||
33 | [ssh-add.c ssh-agent.c ssh-dss.c ssh-ecdsa.c ssh-ed25519.c | ||
34 | [ssh-keygen.c ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c | ||
35 | [ssh-rsa.c sshbuf-misc.c sshbuf.h sshconnect.c sshconnect1.c | ||
36 | [sshconnect2.c sshd.c sshkey.c sshkey.h | ||
37 | [openbsd-compat/openssl-compat.c openbsd-compat/openssl-compat.h] | ||
38 | New key API: refactor key-related functions to be more library-like, | ||
39 | existing API is offered as a set of wrappers. | ||
40 | |||
41 | with and ok markus@ | ||
42 | |||
43 | Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew | ||
44 | Dempsky and Ron Bowes for a detailed review a few months ago. | ||
45 | NB. This commit also removes portable OpenSSH support for OpenSSL | ||
46 | <0.9.8e. | ||
27 | 47 | ||
28 | 20140618 | 48 | 20140618 |
29 | - (tim) [openssh/session.c] Work around to get chroot sftp working on UnixWare | 49 | - (tim) [openssh/session.c] Work around to get chroot sftp working on UnixWare |
diff --git a/Makefile.in b/Makefile.in index 6bca5b51e..16659c0b1 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -1,4 +1,4 @@ | |||
1 | # $Id: Makefile.in,v 1.359 2014/05/21 22:23:59 djm Exp $ | 1 | # $Id: Makefile.in,v 1.360 2014/07/02 05:28:03 djm Exp $ |
2 | 2 | ||
3 | # uncomment if you run a non bourne compatable shell. Ie. csh | 3 | # uncomment if you run a non bourne compatable shell. Ie. csh |
4 | #SHELL = @SH@ | 4 | #SHELL = @SH@ |
@@ -68,7 +68,8 @@ LIBOPENSSH_OBJS=\ | |||
68 | sshbuf.o \ | 68 | sshbuf.o \ |
69 | sshbuf-getput-basic.o \ | 69 | sshbuf-getput-basic.o \ |
70 | sshbuf-misc.o \ | 70 | sshbuf-misc.o \ |
71 | sshbuf-getput-crypto.o | 71 | sshbuf-getput-crypto.o \ |
72 | sshkey.o | ||
72 | 73 | ||
73 | LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ | 74 | LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ |
74 | authfd.o authfile.o bufaux.o bufbn.o buffer.o \ | 75 | authfd.o authfile.o bufaux.o bufbn.o buffer.o \ |
diff --git a/auth-bsdauth.c b/auth-bsdauth.c index f4209c22a..37ff893e6 100644 --- a/auth-bsdauth.c +++ b/auth-bsdauth.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth-bsdauth.c,v 1.12 2014/03/12 04:50:32 djm Exp $ */ | 1 | /* $OpenBSD: auth-bsdauth.c,v 1.13 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -26,6 +26,8 @@ | |||
26 | #include "includes.h" | 26 | #include "includes.h" |
27 | 27 | ||
28 | #include <sys/types.h> | 28 | #include <sys/types.h> |
29 | #include <stdarg.h> | ||
30 | #include <stdio.h> | ||
29 | 31 | ||
30 | #include <stdarg.h> | 32 | #include <stdarg.h> |
31 | 33 | ||
diff --git a/auth-chall.c b/auth-chall.c index 0005aa88b..cb3d522d9 100644 --- a/auth-chall.c +++ b/auth-chall.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth-chall.c,v 1.13 2013/05/17 00:13:13 djm Exp $ */ | 1 | /* $OpenBSD: auth-chall.c,v 1.14 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -26,6 +26,9 @@ | |||
26 | #include "includes.h" | 26 | #include "includes.h" |
27 | 27 | ||
28 | #include <sys/types.h> | 28 | #include <sys/types.h> |
29 | #include <stdarg.h> | ||
30 | #include <stdlib.h> | ||
31 | #include <stdio.h> | ||
29 | 32 | ||
30 | #include <stdarg.h> | 33 | #include <stdarg.h> |
31 | 34 | ||
diff --git a/auth-options.c b/auth-options.c index fa209eaab..9a3c270e9 100644 --- a/auth-options.c +++ b/auth-options.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth-options.c,v 1.62 2013/12/19 00:27:57 djm Exp $ */ | 1 | /* $OpenBSD: auth-options.c,v 1.63 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -586,8 +586,8 @@ auth_cert_options(Key *k, struct passwd *pw) | |||
586 | 586 | ||
587 | if (key_cert_is_legacy(k)) { | 587 | if (key_cert_is_legacy(k)) { |
588 | /* All options are in the one field for v00 certs */ | 588 | /* All options are in the one field for v00 certs */ |
589 | if (parse_option_list(buffer_ptr(&k->cert->critical), | 589 | if (parse_option_list(buffer_ptr(k->cert->critical), |
590 | buffer_len(&k->cert->critical), pw, | 590 | buffer_len(k->cert->critical), pw, |
591 | OPTIONS_CRITICAL|OPTIONS_EXTENSIONS, 1, | 591 | OPTIONS_CRITICAL|OPTIONS_EXTENSIONS, 1, |
592 | &cert_no_port_forwarding_flag, | 592 | &cert_no_port_forwarding_flag, |
593 | &cert_no_agent_forwarding_flag, | 593 | &cert_no_agent_forwarding_flag, |
@@ -599,14 +599,14 @@ auth_cert_options(Key *k, struct passwd *pw) | |||
599 | return -1; | 599 | return -1; |
600 | } else { | 600 | } else { |
601 | /* Separate options and extensions for v01 certs */ | 601 | /* Separate options and extensions for v01 certs */ |
602 | if (parse_option_list(buffer_ptr(&k->cert->critical), | 602 | if (parse_option_list(buffer_ptr(k->cert->critical), |
603 | buffer_len(&k->cert->critical), pw, | 603 | buffer_len(k->cert->critical), pw, |
604 | OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL, | 604 | OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL, |
605 | &cert_forced_command, | 605 | &cert_forced_command, |
606 | &cert_source_address_done) == -1) | 606 | &cert_source_address_done) == -1) |
607 | return -1; | 607 | return -1; |
608 | if (parse_option_list(buffer_ptr(&k->cert->extensions), | 608 | if (parse_option_list(buffer_ptr(k->cert->extensions), |
609 | buffer_len(&k->cert->extensions), pw, | 609 | buffer_len(k->cert->extensions), pw, |
610 | OPTIONS_EXTENSIONS, 1, | 610 | OPTIONS_EXTENSIONS, 1, |
611 | &cert_no_port_forwarding_flag, | 611 | &cert_no_port_forwarding_flag, |
612 | &cert_no_agent_forwarding_flag, | 612 | &cert_no_agent_forwarding_flag, |
diff --git a/auth-rsa.c b/auth-rsa.c index 5dad6c3dc..1bddfa02f 100644 --- a/auth-rsa.c +++ b/auth-rsa.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth-rsa.c,v 1.86 2014/01/27 19:18:54 markus Exp $ */ | 1 | /* $OpenBSD: auth-rsa.c,v 1.87 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -144,7 +144,8 @@ auth_rsa_challenge_dialog(Key *key) | |||
144 | challenge = PRIVSEP(auth_rsa_generate_challenge(key)); | 144 | challenge = PRIVSEP(auth_rsa_generate_challenge(key)); |
145 | 145 | ||
146 | /* Encrypt the challenge with the public key. */ | 146 | /* Encrypt the challenge with the public key. */ |
147 | rsa_public_encrypt(encrypted_challenge, challenge, key->rsa); | 147 | if (rsa_public_encrypt(encrypted_challenge, challenge, key->rsa) != 0) |
148 | fatal("%s: rsa_public_encrypt failed", __func__); | ||
148 | 149 | ||
149 | /* Send the encrypted challenge to the client. */ | 150 | /* Send the encrypted challenge to the client. */ |
150 | packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); | 151 | packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); |
diff --git a/auth2-none.c b/auth2-none.c index c8c6c74a9..5501b9d64 100644 --- a/auth2-none.c +++ b/auth2-none.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-none.c,v 1.16 2010/06/25 08:46:17 djm Exp $ */ | 1 | /* $OpenBSD: auth2-none.c,v 1.17 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -30,9 +30,10 @@ | |||
30 | #include <sys/uio.h> | 30 | #include <sys/uio.h> |
31 | 31 | ||
32 | #include <fcntl.h> | 32 | #include <fcntl.h> |
33 | #include <stdarg.h> | ||
34 | #include <string.h> | 33 | #include <string.h> |
35 | #include <unistd.h> | 34 | #include <unistd.h> |
35 | #include <stdarg.h> | ||
36 | #include <stdio.h> | ||
36 | 37 | ||
37 | #include "atomicio.h" | 38 | #include "atomicio.h" |
38 | #include "xmalloc.h" | 39 | #include "xmalloc.h" |
diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 0fd27bb92..b2fd07a61 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-pubkey.c,v 1.39 2013/12/30 23:52:27 djm Exp $ */ | 1 | /* $OpenBSD: auth2-pubkey.c,v 1.40 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -230,7 +230,7 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) | |||
230 | } | 230 | } |
231 | 231 | ||
232 | static int | 232 | static int |
233 | match_principals_option(const char *principal_list, struct KeyCert *cert) | 233 | match_principals_option(const char *principal_list, struct sshkey_cert *cert) |
234 | { | 234 | { |
235 | char *result; | 235 | char *result; |
236 | u_int i; | 236 | u_int i; |
@@ -250,7 +250,7 @@ match_principals_option(const char *principal_list, struct KeyCert *cert) | |||
250 | } | 250 | } |
251 | 251 | ||
252 | static int | 252 | static int |
253 | match_principals_file(char *file, struct passwd *pw, struct KeyCert *cert) | 253 | match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) |
254 | { | 254 | { |
255 | FILE *f; | 255 | FILE *f; |
256 | char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; | 256 | char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; |
diff --git a/authfile.c b/authfile.c index 7cb901133..e93d86738 100644 --- a/authfile.c +++ b/authfile.c | |||
@@ -1,18 +1,5 @@ | |||
1 | /* $OpenBSD: authfile.c,v 1.106 2014/04/29 18:01:49 markus Exp $ */ | 1 | /* $OpenBSD: authfile.c,v 1.107 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | ||
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||
5 | * All rights reserved | ||
6 | * This file contains functions for reading and writing identity files, and | ||
7 | * for reading the passphrase from the user. | ||
8 | * | ||
9 | * As far as I am concerned, the code I have written for this software | ||
10 | * can be used freely for any purpose. Any derived versions of this | ||
11 | * software must be clearly marked as such, and if the derived work is | ||
12 | * incompatible with the protocol description in the RFC file, it must be | ||
13 | * called by a name other than "ssh" or "Secure Shell". | ||
14 | * | ||
15 | * | ||
16 | * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. |
17 | * | 4 | * |
18 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
@@ -43,32 +30,15 @@ | |||
43 | #include <sys/param.h> | 30 | #include <sys/param.h> |
44 | #include <sys/uio.h> | 31 | #include <sys/uio.h> |
45 | 32 | ||
46 | #ifdef WITH_OPENSSL | ||
47 | #include <openssl/err.h> | ||
48 | #include <openssl/evp.h> | ||
49 | #include <openssl/pem.h> | ||
50 | #endif | ||
51 | |||
52 | /* compatibility with old or broken OpenSSL versions */ | ||
53 | #include "openbsd-compat/openssl-compat.h" | ||
54 | |||
55 | #include "crypto_api.h" | ||
56 | |||
57 | #include <errno.h> | 33 | #include <errno.h> |
58 | #include <fcntl.h> | 34 | #include <fcntl.h> |
59 | #include <stdarg.h> | ||
60 | #include <stdio.h> | 35 | #include <stdio.h> |
36 | #include <stdarg.h> | ||
61 | #include <stdlib.h> | 37 | #include <stdlib.h> |
62 | #include <string.h> | 38 | #include <string.h> |
63 | #include <unistd.h> | 39 | #include <unistd.h> |
64 | 40 | ||
65 | #ifdef HAVE_UTIL_H | ||
66 | #include <util.h> | ||
67 | #endif | ||
68 | |||
69 | #include "xmalloc.h" | ||
70 | #include "cipher.h" | 41 | #include "cipher.h" |
71 | #include "buffer.h" | ||
72 | #include "key.h" | 42 | #include "key.h" |
73 | #include "ssh.h" | 43 | #include "ssh.h" |
74 | #include "log.h" | 44 | #include "log.h" |
@@ -76,667 +46,92 @@ | |||
76 | #include "rsa.h" | 46 | #include "rsa.h" |
77 | #include "misc.h" | 47 | #include "misc.h" |
78 | #include "atomicio.h" | 48 | #include "atomicio.h" |
79 | #include "uuencode.h" | 49 | #include "sshbuf.h" |
80 | 50 | #include "ssherr.h" | |
81 | /* openssh private key file format */ | ||
82 | #define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" | ||
83 | #define MARK_END "-----END OPENSSH PRIVATE KEY-----\n" | ||
84 | #define KDFNAME "bcrypt" | ||
85 | #define AUTH_MAGIC "openssh-key-v1" | ||
86 | #define SALT_LEN 16 | ||
87 | #define DEFAULT_CIPHERNAME "aes256-cbc" | ||
88 | #define DEFAULT_ROUNDS 16 | ||
89 | 51 | ||
90 | #define MAX_KEY_FILE_SIZE (1024 * 1024) | 52 | #define MAX_KEY_FILE_SIZE (1024 * 1024) |
91 | 53 | ||
92 | /* Version identification string for SSH v1 identity files. */ | ||
93 | static const char authfile_id_string[] = | ||
94 | "SSH PRIVATE KEY FILE FORMAT 1.1\n"; | ||
95 | |||
96 | static int | ||
97 | key_private_to_blob2(Key *prv, Buffer *blob, const char *passphrase, | ||
98 | const char *comment, const char *ciphername, int rounds) | ||
99 | { | ||
100 | u_char *key, *cp, salt[SALT_LEN]; | ||
101 | size_t keylen, ivlen, blocksize, authlen; | ||
102 | u_int len, check; | ||
103 | int i, n; | ||
104 | const Cipher *c; | ||
105 | Buffer encoded, b, kdf; | ||
106 | CipherContext ctx; | ||
107 | const char *kdfname = KDFNAME; | ||
108 | |||
109 | if (rounds <= 0) | ||
110 | rounds = DEFAULT_ROUNDS; | ||
111 | if (passphrase == NULL || !strlen(passphrase)) { | ||
112 | ciphername = "none"; | ||
113 | kdfname = "none"; | ||
114 | } else if (ciphername == NULL) | ||
115 | ciphername = DEFAULT_CIPHERNAME; | ||
116 | else if (cipher_number(ciphername) != SSH_CIPHER_SSH2) | ||
117 | fatal("invalid cipher"); | ||
118 | |||
119 | if ((c = cipher_by_name(ciphername)) == NULL) | ||
120 | fatal("unknown cipher name"); | ||
121 | buffer_init(&kdf); | ||
122 | blocksize = cipher_blocksize(c); | ||
123 | keylen = cipher_keylen(c); | ||
124 | ivlen = cipher_ivlen(c); | ||
125 | authlen = cipher_authlen(c); | ||
126 | key = xcalloc(1, keylen + ivlen); | ||
127 | if (strcmp(kdfname, "none") != 0) { | ||
128 | arc4random_buf(salt, SALT_LEN); | ||
129 | if (bcrypt_pbkdf(passphrase, strlen(passphrase), | ||
130 | salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) | ||
131 | fatal("bcrypt_pbkdf failed"); | ||
132 | buffer_put_string(&kdf, salt, SALT_LEN); | ||
133 | buffer_put_int(&kdf, rounds); | ||
134 | } | ||
135 | cipher_init(&ctx, c, key, keylen, key + keylen , ivlen, 1); | ||
136 | explicit_bzero(key, keylen + ivlen); | ||
137 | free(key); | ||
138 | |||
139 | buffer_init(&encoded); | ||
140 | buffer_append(&encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC)); | ||
141 | buffer_put_cstring(&encoded, ciphername); | ||
142 | buffer_put_cstring(&encoded, kdfname); | ||
143 | buffer_put_string(&encoded, buffer_ptr(&kdf), buffer_len(&kdf)); | ||
144 | buffer_put_int(&encoded, 1); /* number of keys */ | ||
145 | key_to_blob(prv, &cp, &len); /* public key */ | ||
146 | buffer_put_string(&encoded, cp, len); | ||
147 | |||
148 | explicit_bzero(cp, len); | ||
149 | free(cp); | ||
150 | |||
151 | buffer_free(&kdf); | ||
152 | |||
153 | /* set up the buffer that will be encrypted */ | ||
154 | buffer_init(&b); | ||
155 | |||
156 | /* Random check bytes */ | ||
157 | check = arc4random(); | ||
158 | buffer_put_int(&b, check); | ||
159 | buffer_put_int(&b, check); | ||
160 | |||
161 | /* append private key and comment*/ | ||
162 | key_private_serialize(prv, &b); | ||
163 | buffer_put_cstring(&b, comment); | ||
164 | |||
165 | /* padding */ | ||
166 | i = 0; | ||
167 | while (buffer_len(&b) % blocksize) | ||
168 | buffer_put_char(&b, ++i & 0xff); | ||
169 | |||
170 | /* length */ | ||
171 | buffer_put_int(&encoded, buffer_len(&b)); | ||
172 | |||
173 | /* encrypt */ | ||
174 | cp = buffer_append_space(&encoded, buffer_len(&b) + authlen); | ||
175 | if (cipher_crypt(&ctx, 0, cp, buffer_ptr(&b), buffer_len(&b), 0, | ||
176 | authlen) != 0) | ||
177 | fatal("%s: cipher_crypt failed", __func__); | ||
178 | buffer_free(&b); | ||
179 | cipher_cleanup(&ctx); | ||
180 | |||
181 | /* uuencode */ | ||
182 | len = 2 * buffer_len(&encoded); | ||
183 | cp = xmalloc(len); | ||
184 | n = uuencode(buffer_ptr(&encoded), buffer_len(&encoded), | ||
185 | (char *)cp, len); | ||
186 | if (n < 0) | ||
187 | fatal("%s: uuencode", __func__); | ||
188 | |||
189 | buffer_clear(blob); | ||
190 | buffer_append(blob, MARK_BEGIN, sizeof(MARK_BEGIN) - 1); | ||
191 | for (i = 0; i < n; i++) { | ||
192 | buffer_put_char(blob, cp[i]); | ||
193 | if (i % 70 == 69) | ||
194 | buffer_put_char(blob, '\n'); | ||
195 | } | ||
196 | if (i % 70 != 69) | ||
197 | buffer_put_char(blob, '\n'); | ||
198 | buffer_append(blob, MARK_END, sizeof(MARK_END) - 1); | ||
199 | free(cp); | ||
200 | |||
201 | return buffer_len(blob); | ||
202 | } | ||
203 | |||
204 | static Key * | ||
205 | key_parse_private2(Buffer *blob, int type, const char *passphrase, | ||
206 | char **commentp) | ||
207 | { | ||
208 | u_char *key = NULL, *cp, *salt = NULL, pad, last; | ||
209 | char *comment = NULL, *ciphername = NULL, *kdfname = NULL; | ||
210 | const u_char *kdfp; | ||
211 | u_int keylen = 0, ivlen, blocksize, slen, klen, len, rounds, nkeys; | ||
212 | u_int check1, check2, m1len, m2len; | ||
213 | size_t authlen; | ||
214 | const Cipher *c; | ||
215 | Buffer b, encoded, copy, kdf; | ||
216 | CipherContext ctx; | ||
217 | Key *k = NULL; | ||
218 | int dlen, ret, i; | ||
219 | |||
220 | buffer_init(&b); | ||
221 | buffer_init(&kdf); | ||
222 | buffer_init(&encoded); | ||
223 | buffer_init(©); | ||
224 | |||
225 | /* uudecode */ | ||
226 | m1len = sizeof(MARK_BEGIN) - 1; | ||
227 | m2len = sizeof(MARK_END) - 1; | ||
228 | cp = buffer_ptr(blob); | ||
229 | len = buffer_len(blob); | ||
230 | if (len < m1len || memcmp(cp, MARK_BEGIN, m1len)) { | ||
231 | debug("%s: missing begin marker", __func__); | ||
232 | goto out; | ||
233 | } | ||
234 | cp += m1len; | ||
235 | len -= m1len; | ||
236 | while (len) { | ||
237 | if (*cp != '\n' && *cp != '\r') | ||
238 | buffer_put_char(&encoded, *cp); | ||
239 | last = *cp; | ||
240 | len--; | ||
241 | cp++; | ||
242 | if (last == '\n') { | ||
243 | if (len >= m2len && !memcmp(cp, MARK_END, m2len)) { | ||
244 | buffer_put_char(&encoded, '\0'); | ||
245 | break; | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | if (!len) { | ||
250 | debug("%s: no end marker", __func__); | ||
251 | goto out; | ||
252 | } | ||
253 | len = buffer_len(&encoded); | ||
254 | if ((cp = buffer_append_space(©, len)) == NULL) { | ||
255 | error("%s: buffer_append_space", __func__); | ||
256 | goto out; | ||
257 | } | ||
258 | if ((dlen = uudecode(buffer_ptr(&encoded), cp, len)) < 0) { | ||
259 | error("%s: uudecode failed", __func__); | ||
260 | goto out; | ||
261 | } | ||
262 | if ((u_int)dlen > len) { | ||
263 | error("%s: crazy uudecode length %d > %u", __func__, dlen, len); | ||
264 | goto out; | ||
265 | } | ||
266 | buffer_consume_end(©, len - dlen); | ||
267 | if (buffer_len(©) < sizeof(AUTH_MAGIC) || | ||
268 | memcmp(buffer_ptr(©), AUTH_MAGIC, sizeof(AUTH_MAGIC))) { | ||
269 | error("%s: bad magic", __func__); | ||
270 | goto out; | ||
271 | } | ||
272 | buffer_consume(©, sizeof(AUTH_MAGIC)); | ||
273 | |||
274 | ciphername = buffer_get_cstring_ret(©, NULL); | ||
275 | if (ciphername == NULL || | ||
276 | (c = cipher_by_name(ciphername)) == NULL) { | ||
277 | error("%s: unknown cipher name", __func__); | ||
278 | goto out; | ||
279 | } | ||
280 | if ((passphrase == NULL || !strlen(passphrase)) && | ||
281 | strcmp(ciphername, "none") != 0) { | ||
282 | /* passphrase required */ | ||
283 | goto out; | ||
284 | } | ||
285 | kdfname = buffer_get_cstring_ret(©, NULL); | ||
286 | if (kdfname == NULL || | ||
287 | (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0)) { | ||
288 | error("%s: unknown kdf name", __func__); | ||
289 | goto out; | ||
290 | } | ||
291 | if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) { | ||
292 | error("%s: cipher %s requires kdf", __func__, ciphername); | ||
293 | goto out; | ||
294 | } | ||
295 | /* kdf options */ | ||
296 | kdfp = buffer_get_string_ptr_ret(©, &klen); | ||
297 | if (kdfp == NULL) { | ||
298 | error("%s: kdf options not set", __func__); | ||
299 | goto out; | ||
300 | } | ||
301 | if (klen > 0) { | ||
302 | if ((cp = buffer_append_space(&kdf, klen)) == NULL) { | ||
303 | error("%s: kdf alloc failed", __func__); | ||
304 | goto out; | ||
305 | } | ||
306 | memcpy(cp, kdfp, klen); | ||
307 | } | ||
308 | /* number of keys */ | ||
309 | if (buffer_get_int_ret(&nkeys, ©) < 0) { | ||
310 | error("%s: key counter missing", __func__); | ||
311 | goto out; | ||
312 | } | ||
313 | if (nkeys != 1) { | ||
314 | error("%s: only one key supported", __func__); | ||
315 | goto out; | ||
316 | } | ||
317 | /* pubkey */ | ||
318 | if ((cp = buffer_get_string_ret(©, &len)) == NULL) { | ||
319 | error("%s: pubkey not found", __func__); | ||
320 | goto out; | ||
321 | } | ||
322 | free(cp); /* XXX check pubkey against decrypted private key */ | ||
323 | |||
324 | /* size of encrypted key blob */ | ||
325 | len = buffer_get_int(©); | ||
326 | blocksize = cipher_blocksize(c); | ||
327 | authlen = cipher_authlen(c); | ||
328 | if (len < blocksize) { | ||
329 | error("%s: encrypted data too small", __func__); | ||
330 | goto out; | ||
331 | } | ||
332 | if (len % blocksize) { | ||
333 | error("%s: length not multiple of blocksize", __func__); | ||
334 | goto out; | ||
335 | } | ||
336 | |||
337 | /* setup key */ | ||
338 | keylen = cipher_keylen(c); | ||
339 | ivlen = cipher_ivlen(c); | ||
340 | key = xcalloc(1, keylen + ivlen); | ||
341 | if (!strcmp(kdfname, "bcrypt")) { | ||
342 | if ((salt = buffer_get_string_ret(&kdf, &slen)) == NULL) { | ||
343 | error("%s: salt not set", __func__); | ||
344 | goto out; | ||
345 | } | ||
346 | if (buffer_get_int_ret(&rounds, &kdf) < 0) { | ||
347 | error("%s: rounds not set", __func__); | ||
348 | goto out; | ||
349 | } | ||
350 | if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen, | ||
351 | key, keylen + ivlen, rounds) < 0) { | ||
352 | error("%s: bcrypt_pbkdf failed", __func__); | ||
353 | goto out; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | cp = buffer_append_space(&b, len); | ||
358 | cipher_init(&ctx, c, key, keylen, key + keylen, ivlen, 0); | ||
359 | ret = cipher_crypt(&ctx, 0, cp, buffer_ptr(©), len, 0, authlen); | ||
360 | cipher_cleanup(&ctx); | ||
361 | buffer_consume(©, len); | ||
362 | |||
363 | /* fail silently on decryption errors */ | ||
364 | if (ret != 0) { | ||
365 | debug("%s: decrypt failed", __func__); | ||
366 | goto out; | ||
367 | } | ||
368 | |||
369 | if (buffer_len(©) != 0) { | ||
370 | error("%s: key blob has trailing data (len = %u)", __func__, | ||
371 | buffer_len(©)); | ||
372 | goto out; | ||
373 | } | ||
374 | |||
375 | /* check bytes */ | ||
376 | if (buffer_get_int_ret(&check1, &b) < 0 || | ||
377 | buffer_get_int_ret(&check2, &b) < 0) { | ||
378 | error("check bytes missing"); | ||
379 | goto out; | ||
380 | } | ||
381 | if (check1 != check2) { | ||
382 | debug("%s: decrypt failed: 0x%08x != 0x%08x", __func__, | ||
383 | check1, check2); | ||
384 | goto out; | ||
385 | } | ||
386 | |||
387 | k = key_private_deserialize(&b); | ||
388 | |||
389 | /* comment */ | ||
390 | comment = buffer_get_cstring_ret(&b, NULL); | ||
391 | |||
392 | i = 0; | ||
393 | while (buffer_len(&b)) { | ||
394 | if (buffer_get_char_ret(&pad, &b) == -1 || | ||
395 | pad != (++i & 0xff)) { | ||
396 | error("%s: bad padding", __func__); | ||
397 | key_free(k); | ||
398 | k = NULL; | ||
399 | goto out; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | if (k && commentp) { | ||
404 | *commentp = comment; | ||
405 | comment = NULL; | ||
406 | } | ||
407 | |||
408 | /* XXX decode pubkey and check against private */ | ||
409 | out: | ||
410 | free(ciphername); | ||
411 | free(kdfname); | ||
412 | free(salt); | ||
413 | free(comment); | ||
414 | if (key) | ||
415 | explicit_bzero(key, keylen + ivlen); | ||
416 | free(key); | ||
417 | buffer_free(&encoded); | ||
418 | buffer_free(©); | ||
419 | buffer_free(&kdf); | ||
420 | buffer_free(&b); | ||
421 | return k; | ||
422 | } | ||
423 | |||
424 | #ifdef WITH_SSH1 | ||
425 | /* | ||
426 | * Serialises the authentication (private) key to a blob, encrypting it with | ||
427 | * passphrase. The identification of the blob (lowest 64 bits of n) will | ||
428 | * precede the key to provide identification of the key without needing a | ||
429 | * passphrase. | ||
430 | */ | ||
431 | static int | ||
432 | key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase, | ||
433 | const char *comment) | ||
434 | { | ||
435 | Buffer buffer, encrypted; | ||
436 | u_char buf[100], *cp; | ||
437 | int i, cipher_num; | ||
438 | CipherContext ciphercontext; | ||
439 | const Cipher *cipher; | ||
440 | u_int32_t rnd; | ||
441 | |||
442 | /* | ||
443 | * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting | ||
444 | * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. | ||
445 | */ | ||
446 | cipher_num = (strcmp(passphrase, "") == 0) ? | ||
447 | SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER; | ||
448 | if ((cipher = cipher_by_number(cipher_num)) == NULL) | ||
449 | fatal("save_private_key_rsa: bad cipher"); | ||
450 | |||
451 | /* This buffer is used to built the secret part of the private key. */ | ||
452 | buffer_init(&buffer); | ||
453 | |||
454 | /* Put checkbytes for checking passphrase validity. */ | ||
455 | rnd = arc4random(); | ||
456 | buf[0] = rnd & 0xff; | ||
457 | buf[1] = (rnd >> 8) & 0xff; | ||
458 | buf[2] = buf[0]; | ||
459 | buf[3] = buf[1]; | ||
460 | buffer_append(&buffer, buf, 4); | ||
461 | |||
462 | /* | ||
463 | * Store the private key (n and e will not be stored because they | ||
464 | * will be stored in plain text, and storing them also in encrypted | ||
465 | * format would just give known plaintext). | ||
466 | */ | ||
467 | buffer_put_bignum(&buffer, key->rsa->d); | ||
468 | buffer_put_bignum(&buffer, key->rsa->iqmp); | ||
469 | buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */ | ||
470 | buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */ | ||
471 | |||
472 | /* Pad the part to be encrypted until its size is a multiple of 8. */ | ||
473 | while (buffer_len(&buffer) % 8 != 0) | ||
474 | buffer_put_char(&buffer, 0); | ||
475 | |||
476 | /* This buffer will be used to contain the data in the file. */ | ||
477 | buffer_init(&encrypted); | ||
478 | |||
479 | /* First store keyfile id string. */ | ||
480 | for (i = 0; authfile_id_string[i]; i++) | ||
481 | buffer_put_char(&encrypted, authfile_id_string[i]); | ||
482 | buffer_put_char(&encrypted, 0); | ||
483 | |||
484 | /* Store cipher type. */ | ||
485 | buffer_put_char(&encrypted, cipher_num); | ||
486 | buffer_put_int(&encrypted, 0); /* For future extension */ | ||
487 | |||
488 | /* Store public key. This will be in plain text. */ | ||
489 | buffer_put_int(&encrypted, BN_num_bits(key->rsa->n)); | ||
490 | buffer_put_bignum(&encrypted, key->rsa->n); | ||
491 | buffer_put_bignum(&encrypted, key->rsa->e); | ||
492 | buffer_put_cstring(&encrypted, comment); | ||
493 | |||
494 | /* Allocate space for the private part of the key in the buffer. */ | ||
495 | cp = buffer_append_space(&encrypted, buffer_len(&buffer)); | ||
496 | |||
497 | cipher_set_key_string(&ciphercontext, cipher, passphrase, | ||
498 | CIPHER_ENCRYPT); | ||
499 | if (cipher_crypt(&ciphercontext, 0, cp, | ||
500 | buffer_ptr(&buffer), buffer_len(&buffer), 0, 0) != 0) | ||
501 | fatal("%s: cipher_crypt failed", __func__); | ||
502 | cipher_cleanup(&ciphercontext); | ||
503 | explicit_bzero(&ciphercontext, sizeof(ciphercontext)); | ||
504 | |||
505 | /* Destroy temporary data. */ | ||
506 | explicit_bzero(buf, sizeof(buf)); | ||
507 | buffer_free(&buffer); | ||
508 | |||
509 | buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted)); | ||
510 | buffer_free(&encrypted); | ||
511 | |||
512 | return 1; | ||
513 | } | ||
514 | #endif | ||
515 | |||
516 | #ifdef WITH_OPENSSL | ||
517 | /* convert SSH v2 key in OpenSSL PEM format */ | ||
518 | static int | ||
519 | key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase, | ||
520 | const char *comment) | ||
521 | { | ||
522 | int success = 0; | ||
523 | int blen, len = strlen(_passphrase); | ||
524 | u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; | ||
525 | #if (OPENSSL_VERSION_NUMBER < 0x00907000L) | ||
526 | const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; | ||
527 | #else | ||
528 | const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; | ||
529 | #endif | ||
530 | const u_char *bptr; | ||
531 | BIO *bio; | ||
532 | |||
533 | if (len > 0 && len <= 4) { | ||
534 | error("passphrase too short: have %d bytes, need > 4", len); | ||
535 | return 0; | ||
536 | } | ||
537 | if ((bio = BIO_new(BIO_s_mem())) == NULL) { | ||
538 | error("%s: BIO_new failed", __func__); | ||
539 | return 0; | ||
540 | } | ||
541 | switch (key->type) { | ||
542 | case KEY_DSA: | ||
543 | success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, | ||
544 | cipher, passphrase, len, NULL, NULL); | ||
545 | break; | ||
546 | #ifdef OPENSSL_HAS_ECC | ||
547 | case KEY_ECDSA: | ||
548 | success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, | ||
549 | cipher, passphrase, len, NULL, NULL); | ||
550 | break; | ||
551 | #endif | ||
552 | case KEY_RSA: | ||
553 | success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, | ||
554 | cipher, passphrase, len, NULL, NULL); | ||
555 | break; | ||
556 | } | ||
557 | if (success) { | ||
558 | if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) | ||
559 | success = 0; | ||
560 | else | ||
561 | buffer_append(blob, bptr, blen); | ||
562 | } | ||
563 | BIO_free(bio); | ||
564 | return success; | ||
565 | } | ||
566 | #endif | ||
567 | |||
568 | /* Save a key blob to a file */ | 54 | /* Save a key blob to a file */ |
569 | static int | 55 | static int |
570 | key_save_private_blob(Buffer *keybuf, const char *filename) | 56 | sshkey_save_private_blob(struct sshbuf *keybuf, const char *filename) |
571 | { | 57 | { |
572 | int fd; | 58 | int fd, oerrno; |
573 | 59 | ||
574 | if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { | 60 | if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) |
575 | error("open %s failed: %s.", filename, strerror(errno)); | 61 | return SSH_ERR_SYSTEM_ERROR; |
576 | return 0; | 62 | if (atomicio(vwrite, fd, (u_char *)sshbuf_ptr(keybuf), |
577 | } | 63 | sshbuf_len(keybuf)) != sshbuf_len(keybuf)) { |
578 | if (atomicio(vwrite, fd, buffer_ptr(keybuf), | 64 | oerrno = errno; |
579 | buffer_len(keybuf)) != buffer_len(keybuf)) { | ||
580 | error("write to key file %s failed: %s", filename, | ||
581 | strerror(errno)); | ||
582 | close(fd); | 65 | close(fd); |
583 | unlink(filename); | 66 | unlink(filename); |
584 | return 0; | 67 | errno = oerrno; |
68 | return SSH_ERR_SYSTEM_ERROR; | ||
585 | } | 69 | } |
586 | close(fd); | 70 | close(fd); |
587 | return 1; | 71 | return 0; |
588 | } | ||
589 | |||
590 | /* Serialise "key" to buffer "blob" */ | ||
591 | static int | ||
592 | key_private_to_blob(Key *key, Buffer *blob, const char *passphrase, | ||
593 | const char *comment, int force_new_format, const char *new_format_cipher, | ||
594 | int new_format_rounds) | ||
595 | { | ||
596 | switch (key->type) { | ||
597 | #ifdef WITH_SSH1 | ||
598 | case KEY_RSA1: | ||
599 | return key_private_rsa1_to_blob(key, blob, passphrase, comment); | ||
600 | #endif | ||
601 | #ifdef WITH_OPENSSL | ||
602 | case KEY_DSA: | ||
603 | case KEY_ECDSA: | ||
604 | case KEY_RSA: | ||
605 | if (force_new_format) { | ||
606 | return key_private_to_blob2(key, blob, passphrase, | ||
607 | comment, new_format_cipher, new_format_rounds); | ||
608 | } | ||
609 | return key_private_pem_to_blob(key, blob, passphrase, comment); | ||
610 | #endif | ||
611 | case KEY_ED25519: | ||
612 | return key_private_to_blob2(key, blob, passphrase, | ||
613 | comment, new_format_cipher, new_format_rounds); | ||
614 | default: | ||
615 | error("%s: cannot save key type %d", __func__, key->type); | ||
616 | return 0; | ||
617 | } | ||
618 | } | 72 | } |
619 | 73 | ||
620 | int | 74 | int |
621 | key_save_private(Key *key, const char *filename, const char *passphrase, | 75 | sshkey_save_private(struct sshkey *key, const char *filename, |
622 | const char *comment, int force_new_format, const char *new_format_cipher, | 76 | const char *passphrase, const char *comment, |
623 | int new_format_rounds) | 77 | int force_new_format, const char *new_format_cipher, int new_format_rounds) |
624 | { | 78 | { |
625 | Buffer keyblob; | 79 | struct sshbuf *keyblob = NULL; |
626 | int success = 0; | 80 | int r; |
627 | 81 | ||
628 | buffer_init(&keyblob); | 82 | if ((keyblob = sshbuf_new()) == NULL) |
629 | if (!key_private_to_blob(key, &keyblob, passphrase, comment, | 83 | return SSH_ERR_ALLOC_FAIL; |
630 | force_new_format, new_format_cipher, new_format_rounds)) | 84 | if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment, |
85 | force_new_format, new_format_cipher, new_format_rounds)) != 0) | ||
631 | goto out; | 86 | goto out; |
632 | if (!key_save_private_blob(&keyblob, filename)) | 87 | if ((r = sshkey_save_private_blob(keyblob, filename)) != 0) |
633 | goto out; | 88 | goto out; |
634 | success = 1; | 89 | r = 0; |
635 | out: | 90 | out: |
636 | buffer_free(&keyblob); | 91 | sshbuf_free(keyblob); |
637 | return success; | 92 | return r; |
638 | } | ||
639 | |||
640 | #ifdef WITH_SSH1 | ||
641 | /* | ||
642 | * Parse the public, unencrypted portion of a RSA1 key. | ||
643 | */ | ||
644 | static Key * | ||
645 | key_parse_public_rsa1(Buffer *blob, char **commentp) | ||
646 | { | ||
647 | Key *pub; | ||
648 | Buffer copy; | ||
649 | |||
650 | /* Check that it is at least big enough to contain the ID string. */ | ||
651 | if (buffer_len(blob) < sizeof(authfile_id_string)) { | ||
652 | debug3("Truncated RSA1 identifier"); | ||
653 | return NULL; | ||
654 | } | ||
655 | |||
656 | /* | ||
657 | * Make sure it begins with the id string. Consume the id string | ||
658 | * from the buffer. | ||
659 | */ | ||
660 | if (memcmp(buffer_ptr(blob), authfile_id_string, | ||
661 | sizeof(authfile_id_string)) != 0) { | ||
662 | debug3("Incorrect RSA1 identifier"); | ||
663 | return NULL; | ||
664 | } | ||
665 | buffer_init(©); | ||
666 | buffer_append(©, buffer_ptr(blob), buffer_len(blob)); | ||
667 | buffer_consume(©, sizeof(authfile_id_string)); | ||
668 | |||
669 | /* Skip cipher type and reserved data. */ | ||
670 | (void) buffer_get_char(©); /* cipher type */ | ||
671 | (void) buffer_get_int(©); /* reserved */ | ||
672 | |||
673 | /* Read the public key from the buffer. */ | ||
674 | (void) buffer_get_int(©); | ||
675 | pub = key_new(KEY_RSA1); | ||
676 | buffer_get_bignum(©, pub->rsa->n); | ||
677 | buffer_get_bignum(©, pub->rsa->e); | ||
678 | if (commentp) | ||
679 | *commentp = buffer_get_string(©, NULL); | ||
680 | /* The encrypted private part is not parsed by this function. */ | ||
681 | buffer_free(©); | ||
682 | |||
683 | return pub; | ||
684 | } | 93 | } |
685 | #endif | ||
686 | 94 | ||
687 | /* Load a key from a fd into a buffer */ | 95 | /* Load a key from a fd into a buffer */ |
688 | int | 96 | int |
689 | key_load_file(int fd, const char *filename, Buffer *blob) | 97 | sshkey_load_file(int fd, const char *filename, struct sshbuf *blob) |
690 | { | 98 | { |
691 | u_char buf[1024]; | 99 | u_char buf[1024]; |
692 | size_t len; | 100 | size_t len; |
693 | struct stat st; | 101 | struct stat st; |
102 | int r; | ||
694 | 103 | ||
695 | if (fstat(fd, &st) < 0) { | 104 | if (fstat(fd, &st) < 0) |
696 | error("%s: fstat of key file %.200s%sfailed: %.100s", __func__, | 105 | return SSH_ERR_SYSTEM_ERROR; |
697 | filename == NULL ? "" : filename, | ||
698 | filename == NULL ? "" : " ", | ||
699 | strerror(errno)); | ||
700 | return 0; | ||
701 | } | ||
702 | if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && | 106 | if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && |
703 | st.st_size > MAX_KEY_FILE_SIZE) { | 107 | st.st_size > MAX_KEY_FILE_SIZE) |
704 | toobig: | 108 | return SSH_ERR_INVALID_FORMAT; |
705 | error("%s: key file %.200s%stoo large", __func__, | ||
706 | filename == NULL ? "" : filename, | ||
707 | filename == NULL ? "" : " "); | ||
708 | return 0; | ||
709 | } | ||
710 | buffer_clear(blob); | ||
711 | for (;;) { | 109 | for (;;) { |
712 | if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { | 110 | if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { |
713 | if (errno == EPIPE) | 111 | if (errno == EPIPE) |
714 | break; | 112 | break; |
715 | debug("%s: read from key file %.200s%sfailed: %.100s", | 113 | r = SSH_ERR_SYSTEM_ERROR; |
716 | __func__, filename == NULL ? "" : filename, | 114 | goto out; |
717 | filename == NULL ? "" : " ", strerror(errno)); | ||
718 | buffer_clear(blob); | ||
719 | explicit_bzero(buf, sizeof(buf)); | ||
720 | return 0; | ||
721 | } | 115 | } |
722 | buffer_append(blob, buf, len); | 116 | if ((r = sshbuf_put(blob, buf, len)) != 0) |
723 | if (buffer_len(blob) > MAX_KEY_FILE_SIZE) { | 117 | goto out; |
724 | buffer_clear(blob); | 118 | if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) { |
725 | explicit_bzero(buf, sizeof(buf)); | 119 | r = SSH_ERR_INVALID_FORMAT; |
726 | goto toobig; | 120 | goto out; |
727 | } | 121 | } |
728 | } | 122 | } |
729 | explicit_bzero(buf, sizeof(buf)); | ||
730 | if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && | 123 | if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && |
731 | st.st_size != buffer_len(blob)) { | 124 | st.st_size != (off_t)sshbuf_len(blob)) { |
732 | debug("%s: key file %.200s%schanged size while reading", | 125 | r = SSH_ERR_FILE_CHANGED; |
733 | __func__, filename == NULL ? "" : filename, | 126 | goto out; |
734 | filename == NULL ? "" : " "); | ||
735 | buffer_clear(blob); | ||
736 | return 0; | ||
737 | } | 127 | } |
128 | r = 0; | ||
738 | 129 | ||
739 | return 1; | 130 | out: |
131 | explicit_bzero(buf, sizeof(buf)); | ||
132 | if (r != 0) | ||
133 | sshbuf_reset(blob); | ||
134 | return r; | ||
740 | } | 135 | } |
741 | 136 | ||
742 | #ifdef WITH_SSH1 | 137 | #ifdef WITH_SSH1 |
@@ -745,249 +140,65 @@ key_load_file(int fd, const char *filename, Buffer *blob) | |||
745 | * encountered (the file does not exist or is not readable), and the key | 140 | * encountered (the file does not exist or is not readable), and the key |
746 | * otherwise. | 141 | * otherwise. |
747 | */ | 142 | */ |
748 | static Key * | 143 | static int |
749 | key_load_public_rsa1(int fd, const char *filename, char **commentp) | 144 | sshkey_load_public_rsa1(int fd, const char *filename, |
750 | { | 145 | struct sshkey **keyp, char **commentp) |
751 | Buffer buffer; | ||
752 | Key *pub; | ||
753 | |||
754 | buffer_init(&buffer); | ||
755 | if (!key_load_file(fd, filename, &buffer)) { | ||
756 | buffer_free(&buffer); | ||
757 | return NULL; | ||
758 | } | ||
759 | |||
760 | pub = key_parse_public_rsa1(&buffer, commentp); | ||
761 | if (pub == NULL) | ||
762 | debug3("Could not load \"%s\" as a RSA1 public key", filename); | ||
763 | buffer_free(&buffer); | ||
764 | return pub; | ||
765 | } | ||
766 | |||
767 | /* load public key from private-key file, works only for SSH v1 */ | ||
768 | Key * | ||
769 | key_load_public_type(int type, const char *filename, char **commentp) | ||
770 | { | ||
771 | Key *pub; | ||
772 | int fd; | ||
773 | |||
774 | if (type == KEY_RSA1) { | ||
775 | fd = open(filename, O_RDONLY); | ||
776 | if (fd < 0) | ||
777 | return NULL; | ||
778 | pub = key_load_public_rsa1(fd, filename, commentp); | ||
779 | close(fd); | ||
780 | return pub; | ||
781 | } | ||
782 | return NULL; | ||
783 | } | ||
784 | |||
785 | static Key * | ||
786 | key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) | ||
787 | { | 146 | { |
788 | int check1, check2, cipher_type; | 147 | struct sshbuf *b = NULL; |
789 | Buffer decrypted; | 148 | int r; |
790 | u_char *cp; | ||
791 | CipherContext ciphercontext; | ||
792 | const Cipher *cipher; | ||
793 | Key *prv = NULL; | ||
794 | Buffer copy; | ||
795 | |||
796 | /* Check that it is at least big enough to contain the ID string. */ | ||
797 | if (buffer_len(blob) < sizeof(authfile_id_string)) { | ||
798 | debug3("Truncated RSA1 identifier"); | ||
799 | return NULL; | ||
800 | } | ||
801 | |||
802 | /* | ||
803 | * Make sure it begins with the id string. Consume the id string | ||
804 | * from the buffer. | ||
805 | */ | ||
806 | if (memcmp(buffer_ptr(blob), authfile_id_string, | ||
807 | sizeof(authfile_id_string)) != 0) { | ||
808 | debug3("Incorrect RSA1 identifier"); | ||
809 | return NULL; | ||
810 | } | ||
811 | buffer_init(©); | ||
812 | buffer_append(©, buffer_ptr(blob), buffer_len(blob)); | ||
813 | buffer_consume(©, sizeof(authfile_id_string)); | ||
814 | |||
815 | /* Read cipher type. */ | ||
816 | cipher_type = buffer_get_char(©); | ||
817 | (void) buffer_get_int(©); /* Reserved data. */ | ||
818 | |||
819 | /* Read the public key from the buffer. */ | ||
820 | (void) buffer_get_int(©); | ||
821 | prv = key_new_private(KEY_RSA1); | ||
822 | |||
823 | buffer_get_bignum(©, prv->rsa->n); | ||
824 | buffer_get_bignum(©, prv->rsa->e); | ||
825 | if (commentp) | ||
826 | *commentp = buffer_get_string(©, NULL); | ||
827 | else | ||
828 | (void)buffer_get_string_ptr(©, NULL); | ||
829 | |||
830 | /* Check that it is a supported cipher. */ | ||
831 | cipher = cipher_by_number(cipher_type); | ||
832 | if (cipher == NULL) { | ||
833 | debug("Unsupported RSA1 cipher %d", cipher_type); | ||
834 | buffer_free(©); | ||
835 | goto fail; | ||
836 | } | ||
837 | /* Initialize space for decrypted data. */ | ||
838 | buffer_init(&decrypted); | ||
839 | cp = buffer_append_space(&decrypted, buffer_len(©)); | ||
840 | |||
841 | /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ | ||
842 | cipher_set_key_string(&ciphercontext, cipher, passphrase, | ||
843 | CIPHER_DECRYPT); | ||
844 | if (cipher_crypt(&ciphercontext, 0, cp, | ||
845 | buffer_ptr(©), buffer_len(©), 0, 0) != 0) | ||
846 | fatal("%s: cipher_crypt failed", __func__); | ||
847 | cipher_cleanup(&ciphercontext); | ||
848 | explicit_bzero(&ciphercontext, sizeof(ciphercontext)); | ||
849 | buffer_free(©); | ||
850 | |||
851 | check1 = buffer_get_char(&decrypted); | ||
852 | check2 = buffer_get_char(&decrypted); | ||
853 | if (check1 != buffer_get_char(&decrypted) || | ||
854 | check2 != buffer_get_char(&decrypted)) { | ||
855 | if (strcmp(passphrase, "") != 0) | ||
856 | debug("Bad passphrase supplied for RSA1 key"); | ||
857 | /* Bad passphrase. */ | ||
858 | buffer_free(&decrypted); | ||
859 | goto fail; | ||
860 | } | ||
861 | /* Read the rest of the private key. */ | ||
862 | buffer_get_bignum(&decrypted, prv->rsa->d); | ||
863 | buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */ | ||
864 | /* in SSL and SSH v1 p and q are exchanged */ | ||
865 | buffer_get_bignum(&decrypted, prv->rsa->q); /* p */ | ||
866 | buffer_get_bignum(&decrypted, prv->rsa->p); /* q */ | ||
867 | |||
868 | /* calculate p-1 and q-1 */ | ||
869 | rsa_generate_additional_parameters(prv->rsa); | ||
870 | |||
871 | buffer_free(&decrypted); | ||
872 | 149 | ||
873 | /* enable blinding */ | 150 | *keyp = NULL; |
874 | if (RSA_blinding_on(prv->rsa, NULL) != 1) { | ||
875 | error("%s: RSA_blinding_on failed", __func__); | ||
876 | goto fail; | ||
877 | } | ||
878 | return prv; | ||
879 | |||
880 | fail: | ||
881 | if (commentp != NULL) | 151 | if (commentp != NULL) |
882 | free(*commentp); | 152 | *commentp = NULL; |
883 | key_free(prv); | 153 | |
884 | return NULL; | 154 | if ((b = sshbuf_new()) == NULL) |
155 | return SSH_ERR_ALLOC_FAIL; | ||
156 | if ((r = sshkey_load_file(fd, filename, b)) != 0) | ||
157 | goto out; | ||
158 | if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0) | ||
159 | goto out; | ||
160 | r = 0; | ||
161 | out: | ||
162 | sshbuf_free(b); | ||
163 | return r; | ||
885 | } | 164 | } |
886 | #endif | 165 | #endif /* WITH_SSH1 */ |
887 | 166 | ||
888 | #ifdef WITH_OPENSSL | 167 | #ifdef WITH_OPENSSL |
889 | static Key * | 168 | /* XXX Deprecate? */ |
890 | key_parse_private_pem(Buffer *blob, int type, const char *passphrase, | 169 | int |
891 | char **commentp) | 170 | sshkey_load_private_pem(int fd, int type, const char *passphrase, |
171 | struct sshkey **keyp, char **commentp) | ||
892 | { | 172 | { |
893 | EVP_PKEY *pk = NULL; | 173 | struct sshbuf *buffer = NULL; |
894 | Key *prv = NULL; | 174 | int r; |
895 | char *name = "<no key>"; | ||
896 | BIO *bio; | ||
897 | |||
898 | if ((bio = BIO_new_mem_buf(buffer_ptr(blob), | ||
899 | buffer_len(blob))) == NULL) { | ||
900 | error("%s: BIO_new_mem_buf failed", __func__); | ||
901 | return NULL; | ||
902 | } | ||
903 | |||
904 | pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase); | ||
905 | BIO_free(bio); | ||
906 | if (pk == NULL) { | ||
907 | debug("%s: PEM_read_PrivateKey failed", __func__); | ||
908 | (void)ERR_get_error(); | ||
909 | } else if (pk->type == EVP_PKEY_RSA && | ||
910 | (type == KEY_UNSPEC||type==KEY_RSA)) { | ||
911 | prv = key_new(KEY_UNSPEC); | ||
912 | prv->rsa = EVP_PKEY_get1_RSA(pk); | ||
913 | prv->type = KEY_RSA; | ||
914 | name = "rsa w/o comment"; | ||
915 | #ifdef DEBUG_PK | ||
916 | RSA_print_fp(stderr, prv->rsa, 8); | ||
917 | #endif | ||
918 | if (RSA_blinding_on(prv->rsa, NULL) != 1) { | ||
919 | error("%s: RSA_blinding_on failed", __func__); | ||
920 | key_free(prv); | ||
921 | prv = NULL; | ||
922 | } | ||
923 | } else if (pk->type == EVP_PKEY_DSA && | ||
924 | (type == KEY_UNSPEC||type==KEY_DSA)) { | ||
925 | prv = key_new(KEY_UNSPEC); | ||
926 | prv->dsa = EVP_PKEY_get1_DSA(pk); | ||
927 | prv->type = KEY_DSA; | ||
928 | name = "dsa w/o comment"; | ||
929 | #ifdef DEBUG_PK | ||
930 | DSA_print_fp(stderr, prv->dsa, 8); | ||
931 | #endif | ||
932 | #ifdef OPENSSL_HAS_ECC | ||
933 | } else if (pk->type == EVP_PKEY_EC && | ||
934 | (type == KEY_UNSPEC||type==KEY_ECDSA)) { | ||
935 | prv = key_new(KEY_UNSPEC); | ||
936 | prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk); | ||
937 | prv->type = KEY_ECDSA; | ||
938 | if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 || | ||
939 | key_curve_nid_to_name(prv->ecdsa_nid) == NULL || | ||
940 | key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa), | ||
941 | EC_KEY_get0_public_key(prv->ecdsa)) != 0 || | ||
942 | key_ec_validate_private(prv->ecdsa) != 0) { | ||
943 | error("%s: bad ECDSA key", __func__); | ||
944 | key_free(prv); | ||
945 | prv = NULL; | ||
946 | } | ||
947 | name = "ecdsa w/o comment"; | ||
948 | #ifdef DEBUG_PK | ||
949 | if (prv != NULL && prv->ecdsa != NULL) | ||
950 | key_dump_ec_key(prv->ecdsa); | ||
951 | #endif | ||
952 | #endif /* OPENSSL_HAS_ECC */ | ||
953 | } else { | ||
954 | error("%s: PEM_read_PrivateKey: mismatch or " | ||
955 | "unknown EVP_PKEY save_type %d", __func__, pk->save_type); | ||
956 | } | ||
957 | if (pk != NULL) | ||
958 | EVP_PKEY_free(pk); | ||
959 | if (prv != NULL && commentp) | ||
960 | *commentp = xstrdup(name); | ||
961 | debug("read PEM private key done: type %s", | ||
962 | prv ? key_type(prv) : "<unknown>"); | ||
963 | return prv; | ||
964 | } | ||
965 | 175 | ||
966 | Key * | 176 | *keyp = NULL; |
967 | key_load_private_pem(int fd, int type, const char *passphrase, | 177 | if (commentp != NULL) |
968 | char **commentp) | 178 | *commentp = NULL; |
969 | { | ||
970 | Buffer buffer; | ||
971 | Key *prv; | ||
972 | 179 | ||
973 | buffer_init(&buffer); | 180 | if ((buffer = sshbuf_new()) == NULL) |
974 | if (!key_load_file(fd, NULL, &buffer)) { | 181 | return SSH_ERR_ALLOC_FAIL; |
975 | buffer_free(&buffer); | 182 | if ((r = sshkey_load_file(fd, NULL, buffer)) != 0) |
976 | return NULL; | 183 | goto out; |
977 | } | 184 | if ((r = sshkey_parse_private_pem_fileblob(buffer, type, passphrase, |
978 | prv = key_parse_private_pem(&buffer, type, passphrase, commentp); | 185 | keyp, commentp)) != 0) |
979 | buffer_free(&buffer); | 186 | goto out; |
980 | return prv; | 187 | r = 0; |
188 | out: | ||
189 | sshbuf_free(buffer); | ||
190 | return r; | ||
981 | } | 191 | } |
982 | #endif | 192 | #endif /* WITH_OPENSSL */ |
983 | 193 | ||
194 | /* XXX remove error() calls from here? */ | ||
984 | int | 195 | int |
985 | key_perm_ok(int fd, const char *filename) | 196 | sshkey_perm_ok(int fd, const char *filename) |
986 | { | 197 | { |
987 | struct stat st; | 198 | struct stat st; |
988 | 199 | ||
989 | if (fstat(fd, &st) < 0) | 200 | if (fstat(fd, &st) < 0) |
990 | return 0; | 201 | return SSH_ERR_SYSTEM_ERROR; |
991 | /* | 202 | /* |
992 | * if a key owned by the user is accessed, then we check the | 203 | * if a key owned by the user is accessed, then we check the |
993 | * permissions of the file. if the key owned by a different user, | 204 | * permissions of the file. if the key owned by a different user, |
@@ -1002,313 +213,311 @@ key_perm_ok(int fd, const char *filename) | |||
1002 | error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); | 213 | error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
1003 | error("Permissions 0%3.3o for '%s' are too open.", | 214 | error("Permissions 0%3.3o for '%s' are too open.", |
1004 | (u_int)st.st_mode & 0777, filename); | 215 | (u_int)st.st_mode & 0777, filename); |
1005 | error("It is required that your private key files are NOT accessible by others."); | 216 | error("It is recommended that your private key files are NOT accessible by others."); |
1006 | error("This private key will be ignored."); | 217 | error("This private key will be ignored."); |
1007 | return 0; | 218 | return SSH_ERR_KEY_BAD_PERMISSIONS; |
1008 | } | 219 | } |
1009 | return 1; | 220 | return 0; |
1010 | } | 221 | } |
1011 | 222 | ||
1012 | static Key * | 223 | /* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */ |
1013 | key_parse_private_type(Buffer *blob, int type, const char *passphrase, | 224 | int |
1014 | char **commentp) | 225 | sshkey_load_private_type(int type, const char *filename, const char *passphrase, |
226 | struct sshkey **keyp, char **commentp, int *perm_ok) | ||
1015 | { | 227 | { |
1016 | Key *k; | 228 | int fd, r; |
229 | struct sshbuf *buffer = NULL; | ||
1017 | 230 | ||
1018 | switch (type) { | 231 | *keyp = NULL; |
1019 | #ifdef WITH_SSH1 | 232 | if (commentp != NULL) |
1020 | case KEY_RSA1: | 233 | *commentp = NULL; |
1021 | return key_parse_private_rsa1(blob, passphrase, commentp); | ||
1022 | #endif | ||
1023 | #ifdef WITH_OPENSSL | ||
1024 | case KEY_DSA: | ||
1025 | case KEY_ECDSA: | ||
1026 | case KEY_RSA: | ||
1027 | return key_parse_private_pem(blob, type, passphrase, commentp); | ||
1028 | #endif | ||
1029 | case KEY_ED25519: | ||
1030 | return key_parse_private2(blob, type, passphrase, commentp); | ||
1031 | case KEY_UNSPEC: | ||
1032 | if ((k = key_parse_private2(blob, type, passphrase, commentp))) | ||
1033 | return k; | ||
1034 | #ifdef WITH_OPENSSL | ||
1035 | return key_parse_private_pem(blob, type, passphrase, commentp); | ||
1036 | #endif | ||
1037 | default: | ||
1038 | error("%s: cannot parse key type %d", __func__, type); | ||
1039 | break; | ||
1040 | } | ||
1041 | return NULL; | ||
1042 | } | ||
1043 | |||
1044 | Key * | ||
1045 | key_load_private_type(int type, const char *filename, const char *passphrase, | ||
1046 | char **commentp, int *perm_ok) | ||
1047 | { | ||
1048 | int fd; | ||
1049 | Key *ret; | ||
1050 | Buffer buffer; | ||
1051 | 234 | ||
1052 | fd = open(filename, O_RDONLY); | 235 | if ((fd = open(filename, O_RDONLY)) < 0) { |
1053 | if (fd < 0) { | ||
1054 | debug("could not open key file '%s': %s", filename, | ||
1055 | strerror(errno)); | ||
1056 | if (perm_ok != NULL) | 236 | if (perm_ok != NULL) |
1057 | *perm_ok = 0; | 237 | *perm_ok = 0; |
1058 | return NULL; | 238 | return SSH_ERR_SYSTEM_ERROR; |
1059 | } | 239 | } |
1060 | if (!key_perm_ok(fd, filename)) { | 240 | if (sshkey_perm_ok(fd, filename) != 0) { |
1061 | if (perm_ok != NULL) | 241 | if (perm_ok != NULL) |
1062 | *perm_ok = 0; | 242 | *perm_ok = 0; |
1063 | error("bad permissions: ignore key: %s", filename); | 243 | r = SSH_ERR_KEY_BAD_PERMISSIONS; |
1064 | close(fd); | 244 | goto out; |
1065 | return NULL; | ||
1066 | } | 245 | } |
1067 | if (perm_ok != NULL) | 246 | if (perm_ok != NULL) |
1068 | *perm_ok = 1; | 247 | *perm_ok = 1; |
1069 | 248 | ||
1070 | buffer_init(&buffer); | 249 | if ((buffer = sshbuf_new()) == NULL) { |
1071 | if (!key_load_file(fd, filename, &buffer)) { | 250 | r = SSH_ERR_ALLOC_FAIL; |
1072 | buffer_free(&buffer); | 251 | goto out; |
1073 | close(fd); | ||
1074 | return NULL; | ||
1075 | } | 252 | } |
253 | if ((r = sshkey_load_file(fd, filename, buffer)) != 0) | ||
254 | goto out; | ||
255 | if ((r = sshkey_parse_private_fileblob_type(buffer, type, passphrase, | ||
256 | keyp, commentp)) != 0) | ||
257 | goto out; | ||
258 | r = 0; | ||
259 | out: | ||
1076 | close(fd); | 260 | close(fd); |
1077 | ret = key_parse_private_type(&buffer, type, passphrase, commentp); | 261 | if (buffer != NULL) |
1078 | buffer_free(&buffer); | 262 | sshbuf_free(buffer); |
1079 | return ret; | 263 | return r; |
1080 | } | 264 | } |
1081 | 265 | ||
1082 | Key * | 266 | /* XXX this is almost identical to sshkey_load_private_type() */ |
1083 | key_parse_private(Buffer *buffer, const char *filename, | 267 | int |
1084 | const char *passphrase, char **commentp) | 268 | sshkey_load_private(const char *filename, const char *passphrase, |
269 | struct sshkey **keyp, char **commentp) | ||
1085 | { | 270 | { |
1086 | #ifdef WITH_SSH1 | 271 | struct sshbuf *buffer = NULL; |
1087 | Key *pub, *prv; | 272 | int r, fd; |
1088 | 273 | ||
1089 | /* it's a SSH v1 key if the public key part is readable */ | 274 | *keyp = NULL; |
1090 | pub = key_parse_public_rsa1(buffer, commentp); | 275 | if (commentp != NULL) |
1091 | if (pub == NULL) { | 276 | *commentp = NULL; |
1092 | prv = key_parse_private_type(buffer, KEY_UNSPEC, | ||
1093 | passphrase, NULL); | ||
1094 | /* use the filename as a comment for PEM */ | ||
1095 | if (commentp && prv) | ||
1096 | *commentp = xstrdup(filename); | ||
1097 | } else { | ||
1098 | key_free(pub); | ||
1099 | /* key_parse_public_rsa1() has already loaded the comment */ | ||
1100 | prv = key_parse_private_type(buffer, KEY_RSA1, passphrase, | ||
1101 | NULL); | ||
1102 | } | ||
1103 | return prv; | ||
1104 | #else | ||
1105 | return key_parse_private_type(buffer, KEY_UNSPEC, | ||
1106 | passphrase, commentp); | ||
1107 | #endif | ||
1108 | } | ||
1109 | |||
1110 | Key * | ||
1111 | key_load_private(const char *filename, const char *passphrase, | ||
1112 | char **commentp) | ||
1113 | { | ||
1114 | Key *prv; | ||
1115 | Buffer buffer; | ||
1116 | int fd; | ||
1117 | 277 | ||
1118 | fd = open(filename, O_RDONLY); | 278 | if ((fd = open(filename, O_RDONLY)) < 0) |
1119 | if (fd < 0) { | 279 | return SSH_ERR_SYSTEM_ERROR; |
1120 | debug("could not open key file '%s': %s", filename, | 280 | if (sshkey_perm_ok(fd, filename) != 0) { |
1121 | strerror(errno)); | 281 | r = SSH_ERR_KEY_BAD_PERMISSIONS; |
1122 | return NULL; | 282 | goto out; |
1123 | } | ||
1124 | if (!key_perm_ok(fd, filename)) { | ||
1125 | error("bad permissions: ignore key: %s", filename); | ||
1126 | close(fd); | ||
1127 | return NULL; | ||
1128 | } | 283 | } |
1129 | 284 | ||
1130 | buffer_init(&buffer); | 285 | if ((buffer = sshbuf_new()) == NULL) { |
1131 | if (!key_load_file(fd, filename, &buffer)) { | 286 | r = SSH_ERR_ALLOC_FAIL; |
1132 | buffer_free(&buffer); | 287 | goto out; |
1133 | close(fd); | ||
1134 | return NULL; | ||
1135 | } | 288 | } |
289 | if ((r = sshkey_load_file(fd, filename, buffer)) != 0 || | ||
290 | (r = sshkey_parse_private_fileblob(buffer, passphrase, filename, | ||
291 | keyp, commentp)) != 0) | ||
292 | goto out; | ||
293 | r = 0; | ||
294 | out: | ||
1136 | close(fd); | 295 | close(fd); |
1137 | 296 | if (buffer != NULL) | |
1138 | prv = key_parse_private(&buffer, filename, passphrase, commentp); | 297 | sshbuf_free(buffer); |
1139 | buffer_free(&buffer); | 298 | return r; |
1140 | return prv; | ||
1141 | } | 299 | } |
1142 | 300 | ||
1143 | static int | 301 | static int |
1144 | key_try_load_public(Key *k, const char *filename, char **commentp) | 302 | sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp) |
1145 | { | 303 | { |
1146 | FILE *f; | 304 | FILE *f; |
1147 | char line[SSH_MAX_PUBKEY_BYTES]; | 305 | char line[SSH_MAX_PUBKEY_BYTES]; |
1148 | char *cp; | 306 | char *cp; |
1149 | u_long linenum = 0; | 307 | u_long linenum = 0; |
308 | int r; | ||
1150 | 309 | ||
1151 | f = fopen(filename, "r"); | 310 | if (commentp != NULL) |
1152 | if (f != NULL) { | 311 | *commentp = NULL; |
1153 | while (read_keyfile_line(f, filename, line, sizeof(line), | 312 | if ((f = fopen(filename, "r")) == NULL) |
1154 | &linenum) != -1) { | 313 | return SSH_ERR_SYSTEM_ERROR; |
1155 | cp = line; | 314 | while (read_keyfile_line(f, filename, line, sizeof(line), |
1156 | switch (*cp) { | 315 | &linenum) != -1) { |
1157 | case '#': | 316 | cp = line; |
1158 | case '\n': | 317 | switch (*cp) { |
1159 | case '\0': | 318 | case '#': |
1160 | continue; | 319 | case '\n': |
1161 | } | 320 | case '\0': |
1162 | /* Abort loading if this looks like a private key */ | 321 | continue; |
1163 | if (strncmp(cp, "-----BEGIN", 10) == 0) | 322 | } |
1164 | break; | 323 | /* Abort loading if this looks like a private key */ |
1165 | /* Skip leading whitespace. */ | 324 | if (strncmp(cp, "-----BEGIN", 10) == 0 || |
1166 | for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) | 325 | strcmp(cp, "SSH PRIVATE KEY FILE") == 0) |
1167 | ; | 326 | break; |
1168 | if (*cp) { | 327 | /* Skip leading whitespace. */ |
1169 | if (key_read(k, &cp) == 1) { | 328 | for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) |
1170 | cp[strcspn(cp, "\r\n")] = '\0'; | 329 | ; |
1171 | if (commentp) { | 330 | if (*cp) { |
1172 | *commentp = xstrdup(*cp ? | 331 | if ((r = sshkey_read(k, &cp)) == 0) { |
1173 | cp : filename); | 332 | cp[strcspn(cp, "\r\n")] = '\0'; |
1174 | } | 333 | if (commentp) { |
1175 | fclose(f); | 334 | *commentp = strdup(*cp ? |
1176 | return 1; | 335 | cp : filename); |
336 | if (*commentp == NULL) | ||
337 | r = SSH_ERR_ALLOC_FAIL; | ||
1177 | } | 338 | } |
339 | fclose(f); | ||
340 | return r; | ||
1178 | } | 341 | } |
1179 | } | 342 | } |
1180 | fclose(f); | ||
1181 | } | 343 | } |
1182 | return 0; | 344 | fclose(f); |
345 | return SSH_ERR_INVALID_FORMAT; | ||
1183 | } | 346 | } |
1184 | 347 | ||
1185 | /* load public key from ssh v1 private or any pubkey file */ | 348 | /* load public key from ssh v1 private or any pubkey file */ |
1186 | Key * | 349 | int |
1187 | key_load_public(const char *filename, char **commentp) | 350 | sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp) |
1188 | { | 351 | { |
1189 | Key *pub; | 352 | struct sshkey *pub = NULL; |
1190 | char file[MAXPATHLEN]; | 353 | char file[MAXPATHLEN]; |
354 | int r, fd; | ||
355 | |||
356 | if (keyp != NULL) | ||
357 | *keyp = NULL; | ||
358 | if (commentp != NULL) | ||
359 | *commentp = NULL; | ||
1191 | 360 | ||
361 | if ((fd = open(filename, O_RDONLY)) < 0) | ||
362 | goto skip; | ||
1192 | #ifdef WITH_SSH1 | 363 | #ifdef WITH_SSH1 |
1193 | /* try rsa1 private key */ | 364 | /* try rsa1 private key */ |
1194 | pub = key_load_public_type(KEY_RSA1, filename, commentp); | 365 | r = sshkey_load_public_rsa1(fd, filename, keyp, commentp); |
1195 | if (pub != NULL) | 366 | close(fd); |
1196 | return pub; | 367 | switch (r) { |
368 | case SSH_ERR_INTERNAL_ERROR: | ||
369 | case SSH_ERR_ALLOC_FAIL: | ||
370 | case SSH_ERR_INVALID_ARGUMENT: | ||
371 | case SSH_ERR_SYSTEM_ERROR: | ||
372 | case 0: | ||
373 | return r; | ||
374 | } | ||
375 | #endif /* WITH_SSH1 */ | ||
376 | |||
377 | /* try ssh2 public key */ | ||
378 | if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) | ||
379 | return SSH_ERR_ALLOC_FAIL; | ||
380 | if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) { | ||
381 | if (keyp != NULL) | ||
382 | *keyp = pub; | ||
383 | return 0; | ||
384 | } | ||
385 | sshkey_free(pub); | ||
1197 | 386 | ||
387 | #ifdef WITH_SSH1 | ||
1198 | /* try rsa1 public key */ | 388 | /* try rsa1 public key */ |
1199 | pub = key_new(KEY_RSA1); | 389 | if ((pub = sshkey_new(KEY_RSA1)) == NULL) |
1200 | if (key_try_load_public(pub, filename, commentp) == 1) | 390 | return SSH_ERR_ALLOC_FAIL; |
1201 | return pub; | 391 | if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) { |
1202 | key_free(pub); | 392 | if (keyp != NULL) |
1203 | #endif | 393 | *keyp = pub; |
394 | return 0; | ||
395 | } | ||
396 | sshkey_free(pub); | ||
397 | #endif /* WITH_SSH1 */ | ||
1204 | 398 | ||
1205 | /* try ssh2 public key */ | 399 | skip: |
1206 | pub = key_new(KEY_UNSPEC); | 400 | /* try .pub suffix */ |
1207 | if (key_try_load_public(pub, filename, commentp) == 1) | 401 | if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) |
1208 | return pub; | 402 | return SSH_ERR_ALLOC_FAIL; |
403 | r = SSH_ERR_ALLOC_FAIL; /* in case strlcpy or strlcat fail */ | ||
1209 | if ((strlcpy(file, filename, sizeof file) < sizeof(file)) && | 404 | if ((strlcpy(file, filename, sizeof file) < sizeof(file)) && |
1210 | (strlcat(file, ".pub", sizeof file) < sizeof(file)) && | 405 | (strlcat(file, ".pub", sizeof file) < sizeof(file)) && |
1211 | (key_try_load_public(pub, file, commentp) == 1)) | 406 | (r = sshkey_try_load_public(pub, file, commentp)) == 0) { |
1212 | return pub; | 407 | if (keyp != NULL) |
1213 | key_free(pub); | 408 | *keyp = pub; |
1214 | return NULL; | 409 | return 0; |
410 | } | ||
411 | sshkey_free(pub); | ||
412 | return r; | ||
1215 | } | 413 | } |
1216 | 414 | ||
1217 | /* Load the certificate associated with the named private key */ | 415 | /* Load the certificate associated with the named private key */ |
1218 | Key * | 416 | int |
1219 | key_load_cert(const char *filename) | 417 | sshkey_load_cert(const char *filename, struct sshkey **keyp) |
1220 | { | 418 | { |
1221 | Key *pub; | 419 | struct sshkey *pub = NULL; |
1222 | char *file; | 420 | char *file = NULL; |
421 | int r = SSH_ERR_INTERNAL_ERROR; | ||
1223 | 422 | ||
1224 | pub = key_new(KEY_UNSPEC); | 423 | *keyp = NULL; |
1225 | xasprintf(&file, "%s-cert.pub", filename); | 424 | |
1226 | if (key_try_load_public(pub, file, NULL) == 1) { | 425 | if (asprintf(&file, "%s-cert.pub", filename) == -1) |
1227 | free(file); | 426 | return SSH_ERR_ALLOC_FAIL; |
1228 | return pub; | 427 | |
428 | if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) { | ||
429 | goto out; | ||
1229 | } | 430 | } |
1230 | free(file); | 431 | if ((r = sshkey_try_load_public(pub, file, NULL)) != 0) |
1231 | key_free(pub); | 432 | goto out; |
1232 | return NULL; | 433 | |
434 | *keyp = pub; | ||
435 | pub = NULL; | ||
436 | r = 0; | ||
437 | |||
438 | out: | ||
439 | if (file != NULL) | ||
440 | free(file); | ||
441 | if (pub != NULL) | ||
442 | sshkey_free(pub); | ||
443 | return r; | ||
1233 | } | 444 | } |
1234 | 445 | ||
1235 | /* Load private key and certificate */ | 446 | /* Load private key and certificate */ |
1236 | Key * | 447 | int |
1237 | key_load_private_cert(int type, const char *filename, const char *passphrase, | 448 | sshkey_load_private_cert(int type, const char *filename, const char *passphrase, |
1238 | int *perm_ok) | 449 | struct sshkey **keyp, int *perm_ok) |
1239 | { | 450 | { |
1240 | Key *key, *pub; | 451 | struct sshkey *key = NULL, *cert = NULL; |
452 | int r; | ||
453 | |||
454 | *keyp = NULL; | ||
1241 | 455 | ||
1242 | switch (type) { | 456 | switch (type) { |
1243 | #ifdef WITH_OPENSSL | 457 | #ifdef WITH_OPENSSL |
1244 | case KEY_RSA: | 458 | case KEY_RSA: |
1245 | case KEY_DSA: | 459 | case KEY_DSA: |
1246 | case KEY_ECDSA: | 460 | case KEY_ECDSA: |
1247 | #endif | ||
1248 | case KEY_ED25519: | 461 | case KEY_ED25519: |
462 | #endif /* WITH_OPENSSL */ | ||
463 | case KEY_UNSPEC: | ||
1249 | break; | 464 | break; |
1250 | default: | 465 | default: |
1251 | error("%s: unsupported key type", __func__); | 466 | return SSH_ERR_KEY_TYPE_UNKNOWN; |
1252 | return NULL; | ||
1253 | } | 467 | } |
1254 | 468 | ||
1255 | if ((key = key_load_private_type(type, filename, | 469 | if ((r = sshkey_load_private_type(type, filename, |
1256 | passphrase, NULL, perm_ok)) == NULL) | 470 | passphrase, &key, NULL, perm_ok)) != 0 || |
1257 | return NULL; | 471 | (r = sshkey_load_cert(filename, &cert)) != 0) |
1258 | 472 | goto out; | |
1259 | if ((pub = key_load_cert(filename)) == NULL) { | ||
1260 | key_free(key); | ||
1261 | return NULL; | ||
1262 | } | ||
1263 | 473 | ||
1264 | /* Make sure the private key matches the certificate */ | 474 | /* Make sure the private key matches the certificate */ |
1265 | if (key_equal_public(key, pub) == 0) { | 475 | if (sshkey_equal_public(key, cert) == 0) { |
1266 | error("%s: certificate does not match private key %s", | 476 | r = SSH_ERR_KEY_CERT_MISMATCH; |
1267 | __func__, filename); | 477 | goto out; |
1268 | } else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) { | ||
1269 | error("%s: key_to_certified failed", __func__); | ||
1270 | } else { | ||
1271 | key_cert_copy(pub, key); | ||
1272 | key_free(pub); | ||
1273 | return key; | ||
1274 | } | 478 | } |
1275 | 479 | ||
1276 | key_free(key); | 480 | if ((r = sshkey_to_certified(key, sshkey_cert_is_legacy(cert))) != 0 || |
1277 | key_free(pub); | 481 | (r = sshkey_cert_copy(cert, key)) != 0) |
1278 | return NULL; | 482 | goto out; |
483 | r = 0; | ||
484 | *keyp = key; | ||
485 | key = NULL; | ||
486 | out: | ||
487 | if (key != NULL) | ||
488 | sshkey_free(key); | ||
489 | if (cert != NULL) | ||
490 | sshkey_free(cert); | ||
491 | return r; | ||
1279 | } | 492 | } |
1280 | 493 | ||
1281 | /* | 494 | /* |
1282 | * Returns 1 if the specified "key" is listed in the file "filename", | 495 | * Returns success if the specified "key" is listed in the file "filename", |
1283 | * 0 if the key is not listed or -1 on error. | 496 | * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error. |
1284 | * If strict_type is set then the key type must match exactly, | 497 | * If strict_type is set then the key type must match exactly, |
1285 | * otherwise a comparison that ignores certficiate data is performed. | 498 | * otherwise a comparison that ignores certficiate data is performed. |
1286 | */ | 499 | */ |
1287 | int | 500 | int |
1288 | key_in_file(Key *key, const char *filename, int strict_type) | 501 | sshkey_in_file(struct sshkey *key, const char *filename, int strict_type) |
1289 | { | 502 | { |
1290 | FILE *f; | 503 | FILE *f; |
1291 | char line[SSH_MAX_PUBKEY_BYTES]; | 504 | char line[SSH_MAX_PUBKEY_BYTES]; |
1292 | char *cp; | 505 | char *cp; |
1293 | u_long linenum = 0; | 506 | u_long linenum = 0; |
1294 | int ret = 0; | 507 | int r = 0; |
1295 | Key *pub; | 508 | struct sshkey *pub = NULL; |
1296 | int (*key_compare)(const Key *, const Key *) = strict_type ? | 509 | int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) = |
1297 | key_equal : key_equal_public; | 510 | strict_type ? sshkey_equal : sshkey_equal_public; |
1298 | 511 | ||
1299 | if ((f = fopen(filename, "r")) == NULL) { | 512 | if ((f = fopen(filename, "r")) == NULL) { |
1300 | if (errno == ENOENT) { | 513 | if (errno == ENOENT) |
1301 | debug("%s: keyfile \"%s\" missing", __func__, filename); | 514 | return SSH_ERR_KEY_NOT_FOUND; |
1302 | return 0; | 515 | else |
1303 | } else { | 516 | return SSH_ERR_SYSTEM_ERROR; |
1304 | error("%s: could not open keyfile \"%s\": %s", __func__, | ||
1305 | filename, strerror(errno)); | ||
1306 | return -1; | ||
1307 | } | ||
1308 | } | 517 | } |
1309 | 518 | ||
1310 | while (read_keyfile_line(f, filename, line, sizeof(line), | 519 | while (read_keyfile_line(f, filename, line, sizeof(line), |
1311 | &linenum) != -1) { | 520 | &linenum) != -1) { |
1312 | cp = line; | 521 | cp = line; |
1313 | 522 | ||
1314 | /* Skip leading whitespace. */ | 523 | /* Skip leading whitespace. */ |
@@ -1323,18 +532,24 @@ key_in_file(Key *key, const char *filename, int strict_type) | |||
1323 | continue; | 532 | continue; |
1324 | } | 533 | } |
1325 | 534 | ||
1326 | pub = key_new(KEY_UNSPEC); | 535 | if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) { |
1327 | if (key_read(pub, &cp) != 1) { | 536 | r = SSH_ERR_ALLOC_FAIL; |
1328 | key_free(pub); | 537 | goto out; |
1329 | continue; | ||
1330 | } | 538 | } |
1331 | if (key_compare(key, pub)) { | 539 | if ((r = sshkey_read(pub, &cp)) != 0) |
1332 | ret = 1; | 540 | goto out; |
1333 | key_free(pub); | 541 | if (sshkey_compare(key, pub)) { |
1334 | break; | 542 | r = 0; |
543 | goto out; | ||
1335 | } | 544 | } |
1336 | key_free(pub); | 545 | sshkey_free(pub); |
546 | pub = NULL; | ||
1337 | } | 547 | } |
548 | r = SSH_ERR_KEY_NOT_FOUND; | ||
549 | out: | ||
550 | if (pub != NULL) | ||
551 | sshkey_free(pub); | ||
1338 | fclose(f); | 552 | fclose(f); |
1339 | return ret; | 553 | return r; |
1340 | } | 554 | } |
555 | |||
diff --git a/authfile.h b/authfile.h index 8ba1c2dbe..223101202 100644 --- a/authfile.h +++ b/authfile.h | |||
@@ -1,32 +1,51 @@ | |||
1 | /* $OpenBSD: authfile.h,v 1.17 2013/12/06 13:34:54 markus Exp $ */ | 1 | /* $OpenBSD: authfile.h,v 1.18 2014/06/24 01:13:21 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. |
5 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||
6 | * All rights reserved | ||
7 | * | 5 | * |
8 | * As far as I am concerned, the code I have written for this software | 6 | * Redistribution and use in source and binary forms, with or without |
9 | * can be used freely for any purpose. Any derived versions of this | 7 | * modification, are permitted provided that the following conditions |
10 | * software must be clearly marked as such, and if the derived work is | 8 | * are met: |
11 | * incompatible with the protocol description in the RFC file, it must be | 9 | * 1. Redistributions of source code must retain the above copyright |
12 | * called by a name other than "ssh" or "Secure Shell". | 10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
13 | */ | 25 | */ |
14 | 26 | ||
15 | #ifndef AUTHFILE_H | 27 | #ifndef AUTHFILE_H |
16 | #define AUTHFILE_H | 28 | #define AUTHFILE_H |
17 | 29 | ||
18 | int key_save_private(Key *, const char *, const char *, const char *, | 30 | #ifdef WITH_LEAKMALLOC |
19 | int, const char *, int); | 31 | #include "leakmalloc.h" |
20 | int key_load_file(int, const char *, Buffer *); | 32 | #endif |
21 | Key *key_load_cert(const char *); | 33 | |
22 | Key *key_load_public(const char *, char **); | 34 | struct sshbuf; |
23 | Key *key_load_public_type(int, const char *, char **); | 35 | struct sshkey; |
24 | Key *key_parse_private(Buffer *, const char *, const char *, char **); | 36 | |
25 | Key *key_load_private(const char *, const char *, char **); | 37 | int sshkey_save_private(struct sshkey *, const char *, |
26 | Key *key_load_private_cert(int, const char *, const char *, int *); | 38 | const char *, const char *, int, const char *, int); |
27 | Key *key_load_private_type(int, const char *, const char *, char **, int *); | 39 | int sshkey_load_file(int, const char *, struct sshbuf *); |
28 | Key *key_load_private_pem(int, int, const char *, char **); | 40 | int sshkey_load_cert(const char *, struct sshkey **); |
29 | int key_perm_ok(int, const char *); | 41 | int sshkey_load_public(const char *, struct sshkey **, char **); |
30 | int key_in_file(Key *, const char *, int); | 42 | int sshkey_load_private(const char *, const char *, struct sshkey **, char **); |
43 | int sshkey_load_private_cert(int, const char *, const char *, | ||
44 | struct sshkey **, int *); | ||
45 | int sshkey_load_private_type(int, const char *, const char *, | ||
46 | struct sshkey **, char **, int *); | ||
47 | int sshkey_load_private_pem(int, int, const char *, struct sshkey **, char **); | ||
48 | int sshkey_perm_ok(int, const char *); | ||
49 | int sshkey_in_file(struct sshkey *, const char *, int); | ||
31 | 50 | ||
32 | #endif | 51 | #endif |
diff --git a/cipher-3des1.c b/cipher-3des1.c index b2823592b..5361f517d 100644 --- a/cipher-3des1.c +++ b/cipher-3des1.c | |||
@@ -29,13 +29,11 @@ | |||
29 | 29 | ||
30 | #include <openssl/evp.h> | 30 | #include <openssl/evp.h> |
31 | 31 | ||
32 | #include <stdarg.h> | ||
33 | #include <string.h> | 32 | #include <string.h> |
34 | 33 | ||
35 | #include "xmalloc.h" | 34 | #include "xmalloc.h" |
36 | #include "log.h" | 35 | #include "log.h" |
37 | 36 | #include "ssherr.h" | |
38 | #include "openbsd-compat/openssl-compat.h" | ||
39 | 37 | ||
40 | /* | 38 | /* |
41 | * This is used by SSH1: | 39 | * This is used by SSH1: |
@@ -57,7 +55,7 @@ struct ssh1_3des_ctx | |||
57 | }; | 55 | }; |
58 | 56 | ||
59 | const EVP_CIPHER * evp_ssh1_3des(void); | 57 | const EVP_CIPHER * evp_ssh1_3des(void); |
60 | void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); | 58 | int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); |
61 | 59 | ||
62 | static int | 60 | static int |
63 | ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, | 61 | ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, |
@@ -67,11 +65,12 @@ ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, | |||
67 | u_char *k1, *k2, *k3; | 65 | u_char *k1, *k2, *k3; |
68 | 66 | ||
69 | if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { | 67 | if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { |
70 | c = xcalloc(1, sizeof(*c)); | 68 | if ((c = calloc(1, sizeof(*c))) == NULL) |
69 | return 0; | ||
71 | EVP_CIPHER_CTX_set_app_data(ctx, c); | 70 | EVP_CIPHER_CTX_set_app_data(ctx, c); |
72 | } | 71 | } |
73 | if (key == NULL) | 72 | if (key == NULL) |
74 | return (1); | 73 | return 1; |
75 | if (enc == -1) | 74 | if (enc == -1) |
76 | enc = ctx->encrypt; | 75 | enc = ctx->encrypt; |
77 | k1 = k2 = k3 = (u_char *) key; | 76 | k1 = k2 = k3 = (u_char *) key; |
@@ -85,44 +84,29 @@ ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, | |||
85 | EVP_CIPHER_CTX_init(&c->k1); | 84 | EVP_CIPHER_CTX_init(&c->k1); |
86 | EVP_CIPHER_CTX_init(&c->k2); | 85 | EVP_CIPHER_CTX_init(&c->k2); |
87 | EVP_CIPHER_CTX_init(&c->k3); | 86 | EVP_CIPHER_CTX_init(&c->k3); |
88 | #ifdef SSH_OLD_EVP | ||
89 | EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc); | ||
90 | EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc); | ||
91 | EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc); | ||
92 | #else | ||
93 | if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 || | 87 | if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 || |
94 | EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 || | 88 | EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 || |
95 | EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) { | 89 | EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) { |
96 | explicit_bzero(c, sizeof(*c)); | 90 | explicit_bzero(c, sizeof(*c)); |
97 | free(c); | 91 | free(c); |
98 | EVP_CIPHER_CTX_set_app_data(ctx, NULL); | 92 | EVP_CIPHER_CTX_set_app_data(ctx, NULL); |
99 | return (0); | 93 | return 0; |
100 | } | 94 | } |
101 | #endif | 95 | return 1; |
102 | return (1); | ||
103 | } | 96 | } |
104 | 97 | ||
105 | static int | 98 | static int |
106 | ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, | 99 | ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, size_t len) |
107 | LIBCRYPTO_EVP_INL_TYPE len) | ||
108 | { | 100 | { |
109 | struct ssh1_3des_ctx *c; | 101 | struct ssh1_3des_ctx *c; |
110 | 102 | ||
111 | if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { | 103 | if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) |
112 | error("ssh1_3des_cbc: no context"); | 104 | return 0; |
113 | return (0); | ||
114 | } | ||
115 | #ifdef SSH_OLD_EVP | ||
116 | EVP_Cipher(&c->k1, dest, (u_char *)src, len); | ||
117 | EVP_Cipher(&c->k2, dest, dest, len); | ||
118 | EVP_Cipher(&c->k3, dest, dest, len); | ||
119 | #else | ||
120 | if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 || | 105 | if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 || |
121 | EVP_Cipher(&c->k2, dest, dest, len) == 0 || | 106 | EVP_Cipher(&c->k2, dest, dest, len) == 0 || |
122 | EVP_Cipher(&c->k3, dest, dest, len) == 0) | 107 | EVP_Cipher(&c->k3, dest, dest, len) == 0) |
123 | return (0); | 108 | return 0; |
124 | #endif | 109 | return 1; |
125 | return (1); | ||
126 | } | 110 | } |
127 | 111 | ||
128 | static int | 112 | static int |
@@ -138,29 +122,28 @@ ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx) | |||
138 | free(c); | 122 | free(c); |
139 | EVP_CIPHER_CTX_set_app_data(ctx, NULL); | 123 | EVP_CIPHER_CTX_set_app_data(ctx, NULL); |
140 | } | 124 | } |
141 | return (1); | 125 | return 1; |
142 | } | 126 | } |
143 | 127 | ||
144 | void | 128 | int |
145 | ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len) | 129 | ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len) |
146 | { | 130 | { |
147 | struct ssh1_3des_ctx *c; | 131 | struct ssh1_3des_ctx *c; |
148 | 132 | ||
149 | if (len != 24) | 133 | if (len != 24) |
150 | fatal("%s: bad 3des iv length: %d", __func__, len); | 134 | return SSH_ERR_INVALID_ARGUMENT; |
151 | if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL) | 135 | if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL) |
152 | fatal("%s: no 3des context", __func__); | 136 | return SSH_ERR_INTERNAL_ERROR; |
153 | if (doset) { | 137 | if (doset) { |
154 | debug3("%s: Installed 3DES IV", __func__); | ||
155 | memcpy(c->k1.iv, iv, 8); | 138 | memcpy(c->k1.iv, iv, 8); |
156 | memcpy(c->k2.iv, iv + 8, 8); | 139 | memcpy(c->k2.iv, iv + 8, 8); |
157 | memcpy(c->k3.iv, iv + 16, 8); | 140 | memcpy(c->k3.iv, iv + 16, 8); |
158 | } else { | 141 | } else { |
159 | debug3("%s: Copying 3DES IV", __func__); | ||
160 | memcpy(iv, c->k1.iv, 8); | 142 | memcpy(iv, c->k1.iv, 8); |
161 | memcpy(iv + 8, c->k2.iv, 8); | 143 | memcpy(iv + 8, c->k2.iv, 8); |
162 | memcpy(iv + 16, c->k3.iv, 8); | 144 | memcpy(iv + 16, c->k3.iv, 8); |
163 | } | 145 | } |
146 | return 0; | ||
164 | } | 147 | } |
165 | 148 | ||
166 | const EVP_CIPHER * | 149 | const EVP_CIPHER * |
@@ -176,8 +159,6 @@ evp_ssh1_3des(void) | |||
176 | ssh1_3des.init = ssh1_3des_init; | 159 | ssh1_3des.init = ssh1_3des_init; |
177 | ssh1_3des.cleanup = ssh1_3des_cleanup; | 160 | ssh1_3des.cleanup = ssh1_3des_cleanup; |
178 | ssh1_3des.do_cipher = ssh1_3des_cbc; | 161 | ssh1_3des.do_cipher = ssh1_3des_cbc; |
179 | #ifndef SSH_OLD_EVP | ||
180 | ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH; | 162 | ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH; |
181 | #endif | 163 | return &ssh1_3des; |
182 | return (&ssh1_3des); | ||
183 | } | 164 | } |
diff --git a/cipher-chachapoly.c b/cipher-chachapoly.c index 251b94ec8..0caccd297 100644 --- a/cipher-chachapoly.c +++ b/cipher-chachapoly.c | |||
@@ -14,7 +14,7 @@ | |||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | /* $OpenBSD: cipher-chachapoly.c,v 1.4 2014/01/31 16:39:19 tedu Exp $ */ | 17 | /* $OpenBSD: cipher-chachapoly.c,v 1.5 2014/06/24 01:13:21 djm Exp $ */ |
18 | 18 | ||
19 | #include "includes.h" | 19 | #include "includes.h" |
20 | 20 | ||
@@ -24,16 +24,18 @@ | |||
24 | #include <stdio.h> /* needed for misc.h */ | 24 | #include <stdio.h> /* needed for misc.h */ |
25 | 25 | ||
26 | #include "log.h" | 26 | #include "log.h" |
27 | #include "misc.h" | 27 | #include "sshbuf.h" |
28 | #include "ssherr.h" | ||
28 | #include "cipher-chachapoly.h" | 29 | #include "cipher-chachapoly.h" |
29 | 30 | ||
30 | void chachapoly_init(struct chachapoly_ctx *ctx, | 31 | int chachapoly_init(struct chachapoly_ctx *ctx, |
31 | const u_char *key, u_int keylen) | 32 | const u_char *key, u_int keylen) |
32 | { | 33 | { |
33 | if (keylen != (32 + 32)) /* 2 x 256 bit keys */ | 34 | if (keylen != (32 + 32)) /* 2 x 256 bit keys */ |
34 | fatal("%s: invalid keylen %u", __func__, keylen); | 35 | return SSH_ERR_INVALID_ARGUMENT; |
35 | chacha_keysetup(&ctx->main_ctx, key, 256); | 36 | chacha_keysetup(&ctx->main_ctx, key, 256); |
36 | chacha_keysetup(&ctx->header_ctx, key + 32, 256); | 37 | chacha_keysetup(&ctx->header_ctx, key + 32, 256); |
38 | return 0; | ||
37 | } | 39 | } |
38 | 40 | ||
39 | /* | 41 | /* |
@@ -52,14 +54,14 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest, | |||
52 | u_char seqbuf[8]; | 54 | u_char seqbuf[8]; |
53 | const u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */ | 55 | const u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */ |
54 | u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; | 56 | u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; |
55 | int r = -1; | 57 | int r = SSH_ERR_INTERNAL_ERROR; |
56 | 58 | ||
57 | /* | 59 | /* |
58 | * Run ChaCha20 once to generate the Poly1305 key. The IV is the | 60 | * Run ChaCha20 once to generate the Poly1305 key. The IV is the |
59 | * packet sequence number. | 61 | * packet sequence number. |
60 | */ | 62 | */ |
61 | memset(poly_key, 0, sizeof(poly_key)); | 63 | memset(poly_key, 0, sizeof(poly_key)); |
62 | put_u64(seqbuf, seqnr); | 64 | POKE_U64(seqbuf, seqnr); |
63 | chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); | 65 | chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); |
64 | chacha_encrypt_bytes(&ctx->main_ctx, | 66 | chacha_encrypt_bytes(&ctx->main_ctx, |
65 | poly_key, poly_key, sizeof(poly_key)); | 67 | poly_key, poly_key, sizeof(poly_key)); |
@@ -71,8 +73,10 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest, | |||
71 | const u_char *tag = src + aadlen + len; | 73 | const u_char *tag = src + aadlen + len; |
72 | 74 | ||
73 | poly1305_auth(expected_tag, src, aadlen + len, poly_key); | 75 | poly1305_auth(expected_tag, src, aadlen + len, poly_key); |
74 | if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) | 76 | if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) { |
77 | r = SSH_ERR_MAC_INVALID; | ||
75 | goto out; | 78 | goto out; |
79 | } | ||
76 | } | 80 | } |
77 | /* Crypt additional data */ | 81 | /* Crypt additional data */ |
78 | if (aadlen) { | 82 | if (aadlen) { |
@@ -88,7 +92,6 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest, | |||
88 | poly_key); | 92 | poly_key); |
89 | } | 93 | } |
90 | r = 0; | 94 | r = 0; |
91 | |||
92 | out: | 95 | out: |
93 | explicit_bzero(expected_tag, sizeof(expected_tag)); | 96 | explicit_bzero(expected_tag, sizeof(expected_tag)); |
94 | explicit_bzero(seqbuf, sizeof(seqbuf)); | 97 | explicit_bzero(seqbuf, sizeof(seqbuf)); |
@@ -104,11 +107,11 @@ chachapoly_get_length(struct chachapoly_ctx *ctx, | |||
104 | u_char buf[4], seqbuf[8]; | 107 | u_char buf[4], seqbuf[8]; |
105 | 108 | ||
106 | if (len < 4) | 109 | if (len < 4) |
107 | return -1; /* Insufficient length */ | 110 | return SSH_ERR_MESSAGE_INCOMPLETE; |
108 | put_u64(seqbuf, seqnr); | 111 | POKE_U64(seqbuf, seqnr); |
109 | chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); | 112 | chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); |
110 | chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); | 113 | chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); |
111 | *plenp = get_u32(buf); | 114 | *plenp = PEEK_U32(buf); |
112 | return 0; | 115 | return 0; |
113 | } | 116 | } |
114 | 117 | ||
diff --git a/cipher-chachapoly.h b/cipher-chachapoly.h index 7948dcdcd..b7072be7d 100644 --- a/cipher-chachapoly.h +++ b/cipher-chachapoly.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: cipher-chachapoly.h,v 1.3 2014/05/02 03:27:54 djm Exp $ */ | 1 | /* $OpenBSD: cipher-chachapoly.h,v 1.4 2014/06/24 01:13:21 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) Damien Miller 2013 <djm@mindrot.org> | 4 | * Copyright (c) Damien Miller 2013 <djm@mindrot.org> |
@@ -28,7 +28,7 @@ struct chachapoly_ctx { | |||
28 | struct chacha_ctx main_ctx, header_ctx; | 28 | struct chacha_ctx main_ctx, header_ctx; |
29 | }; | 29 | }; |
30 | 30 | ||
31 | void chachapoly_init(struct chachapoly_ctx *cpctx, | 31 | int chachapoly_init(struct chachapoly_ctx *cpctx, |
32 | const u_char *key, u_int keylen) | 32 | const u_char *key, u_int keylen) |
33 | __attribute__((__bounded__(__buffer__, 2, 3))); | 33 | __attribute__((__bounded__(__buffer__, 2, 3))); |
34 | int chachapoly_crypt(struct chachapoly_ctx *cpctx, u_int seqnr, | 34 | int chachapoly_crypt(struct chachapoly_ctx *cpctx, u_int seqnr, |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: cipher.c,v 1.98 2014/04/29 18:01:49 markus Exp $ */ | 1 | /* $OpenBSD: cipher.c,v 1.99 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -43,23 +43,19 @@ | |||
43 | #include <stdarg.h> | 43 | #include <stdarg.h> |
44 | #include <stdio.h> | 44 | #include <stdio.h> |
45 | 45 | ||
46 | #include "xmalloc.h" | ||
47 | #include "log.h" | ||
48 | #include "misc.h" | ||
49 | #include "cipher.h" | 46 | #include "cipher.h" |
50 | #include "buffer.h" | 47 | #include "misc.h" |
48 | #include "sshbuf.h" | ||
49 | #include "ssherr.h" | ||
51 | #include "digest.h" | 50 | #include "digest.h" |
52 | 51 | ||
53 | /* compatibility with old or broken OpenSSL versions */ | ||
54 | #include "openbsd-compat/openssl-compat.h" | ||
55 | |||
56 | #ifdef WITH_SSH1 | 52 | #ifdef WITH_SSH1 |
57 | extern const EVP_CIPHER *evp_ssh1_bf(void); | 53 | extern const EVP_CIPHER *evp_ssh1_bf(void); |
58 | extern const EVP_CIPHER *evp_ssh1_3des(void); | 54 | extern const EVP_CIPHER *evp_ssh1_3des(void); |
59 | extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); | 55 | extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); |
60 | #endif | 56 | #endif |
61 | 57 | ||
62 | struct Cipher { | 58 | struct sshcipher { |
63 | char *name; | 59 | char *name; |
64 | int number; /* for ssh1 only */ | 60 | int number; /* for ssh1 only */ |
65 | u_int block_size; | 61 | u_int block_size; |
@@ -79,12 +75,12 @@ struct Cipher { | |||
79 | #endif | 75 | #endif |
80 | }; | 76 | }; |
81 | 77 | ||
82 | static const struct Cipher ciphers[] = { | 78 | static const struct sshcipher ciphers[] = { |
83 | #ifdef WITH_SSH1 | 79 | #ifdef WITH_SSH1 |
84 | { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, | 80 | { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, |
85 | { "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des }, | 81 | { "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des }, |
86 | { "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, 0, 1, evp_ssh1_bf }, | 82 | { "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, 0, 1, evp_ssh1_bf }, |
87 | #endif | 83 | #endif /* WITH_SSH1 */ |
88 | #ifdef WITH_OPENSSL | 84 | #ifdef WITH_OPENSSL |
89 | { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, | 85 | { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, |
90 | { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc }, | 86 | { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc }, |
@@ -103,12 +99,12 @@ static const struct Cipher ciphers[] = { | |||
103 | { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr }, | 99 | { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr }, |
104 | { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr }, | 100 | { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr }, |
105 | { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr }, | 101 | { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr }, |
106 | #ifdef OPENSSL_HAVE_EVPGCM | 102 | # ifdef OPENSSL_HAVE_EVPGCM |
107 | { "aes128-gcm@openssh.com", | 103 | { "aes128-gcm@openssh.com", |
108 | SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm }, | 104 | SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm }, |
109 | { "aes256-gcm@openssh.com", | 105 | { "aes256-gcm@openssh.com", |
110 | SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, | 106 | SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, |
111 | #endif | 107 | # endif /* OPENSSL_HAVE_EVPGCM */ |
112 | #else /* WITH_OPENSSL */ | 108 | #else /* WITH_OPENSSL */ |
113 | { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, CFLAG_AESCTR, NULL }, | 109 | { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, CFLAG_AESCTR, NULL }, |
114 | { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, CFLAG_AESCTR, NULL }, | 110 | { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, CFLAG_AESCTR, NULL }, |
@@ -117,18 +113,19 @@ static const struct Cipher ciphers[] = { | |||
117 | #endif /* WITH_OPENSSL */ | 113 | #endif /* WITH_OPENSSL */ |
118 | { "chacha20-poly1305@openssh.com", | 114 | { "chacha20-poly1305@openssh.com", |
119 | SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CHACHAPOLY, NULL }, | 115 | SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CHACHAPOLY, NULL }, |
116 | |||
120 | { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } | 117 | { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } |
121 | }; | 118 | }; |
122 | 119 | ||
123 | /*--*/ | 120 | /*--*/ |
124 | 121 | ||
125 | /* Returns a list of supported ciphers separated by the specified char. */ | 122 | /* Returns a comma-separated list of supported ciphers. */ |
126 | char * | 123 | char * |
127 | cipher_alg_list(char sep, int auth_only) | 124 | cipher_alg_list(char sep, int auth_only) |
128 | { | 125 | { |
129 | char *ret = NULL; | 126 | char *tmp, *ret = NULL; |
130 | size_t nlen, rlen = 0; | 127 | size_t nlen, rlen = 0; |
131 | const Cipher *c; | 128 | const struct sshcipher *c; |
132 | 129 | ||
133 | for (c = ciphers; c->name != NULL; c++) { | 130 | for (c = ciphers; c->name != NULL; c++) { |
134 | if (c->number != SSH_CIPHER_SSH2) | 131 | if (c->number != SSH_CIPHER_SSH2) |
@@ -138,7 +135,11 @@ cipher_alg_list(char sep, int auth_only) | |||
138 | if (ret != NULL) | 135 | if (ret != NULL) |
139 | ret[rlen++] = sep; | 136 | ret[rlen++] = sep; |
140 | nlen = strlen(c->name); | 137 | nlen = strlen(c->name); |
141 | ret = xrealloc(ret, 1, rlen + nlen + 2); | 138 | if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { |
139 | free(ret); | ||
140 | return NULL; | ||
141 | } | ||
142 | ret = tmp; | ||
142 | memcpy(ret + rlen, c->name, nlen + 1); | 143 | memcpy(ret + rlen, c->name, nlen + 1); |
143 | rlen += nlen; | 144 | rlen += nlen; |
144 | } | 145 | } |
@@ -146,19 +147,19 @@ cipher_alg_list(char sep, int auth_only) | |||
146 | } | 147 | } |
147 | 148 | ||
148 | u_int | 149 | u_int |
149 | cipher_blocksize(const Cipher *c) | 150 | cipher_blocksize(const struct sshcipher *c) |
150 | { | 151 | { |
151 | return (c->block_size); | 152 | return (c->block_size); |
152 | } | 153 | } |
153 | 154 | ||
154 | u_int | 155 | u_int |
155 | cipher_keylen(const Cipher *c) | 156 | cipher_keylen(const struct sshcipher *c) |
156 | { | 157 | { |
157 | return (c->key_len); | 158 | return (c->key_len); |
158 | } | 159 | } |
159 | 160 | ||
160 | u_int | 161 | u_int |
161 | cipher_seclen(const Cipher *c) | 162 | cipher_seclen(const struct sshcipher *c) |
162 | { | 163 | { |
163 | if (strcmp("3des-cbc", c->name) == 0) | 164 | if (strcmp("3des-cbc", c->name) == 0) |
164 | return 14; | 165 | return 14; |
@@ -166,13 +167,13 @@ cipher_seclen(const Cipher *c) | |||
166 | } | 167 | } |
167 | 168 | ||
168 | u_int | 169 | u_int |
169 | cipher_authlen(const Cipher *c) | 170 | cipher_authlen(const struct sshcipher *c) |
170 | { | 171 | { |
171 | return (c->auth_len); | 172 | return (c->auth_len); |
172 | } | 173 | } |
173 | 174 | ||
174 | u_int | 175 | u_int |
175 | cipher_ivlen(const Cipher *c) | 176 | cipher_ivlen(const struct sshcipher *c) |
176 | { | 177 | { |
177 | /* | 178 | /* |
178 | * Default is cipher block size, except for chacha20+poly1305 that | 179 | * Default is cipher block size, except for chacha20+poly1305 that |
@@ -183,13 +184,13 @@ cipher_ivlen(const Cipher *c) | |||
183 | } | 184 | } |
184 | 185 | ||
185 | u_int | 186 | u_int |
186 | cipher_get_number(const Cipher *c) | 187 | cipher_get_number(const struct sshcipher *c) |
187 | { | 188 | { |
188 | return (c->number); | 189 | return (c->number); |
189 | } | 190 | } |
190 | 191 | ||
191 | u_int | 192 | u_int |
192 | cipher_is_cbc(const Cipher *c) | 193 | cipher_is_cbc(const struct sshcipher *c) |
193 | { | 194 | { |
194 | return (c->flags & CFLAG_CBC) != 0; | 195 | return (c->flags & CFLAG_CBC) != 0; |
195 | } | 196 | } |
@@ -206,20 +207,20 @@ cipher_mask_ssh1(int client) | |||
206 | return mask; | 207 | return mask; |
207 | } | 208 | } |
208 | 209 | ||
209 | const Cipher * | 210 | const struct sshcipher * |
210 | cipher_by_name(const char *name) | 211 | cipher_by_name(const char *name) |
211 | { | 212 | { |
212 | const Cipher *c; | 213 | const struct sshcipher *c; |
213 | for (c = ciphers; c->name != NULL; c++) | 214 | for (c = ciphers; c->name != NULL; c++) |
214 | if (strcmp(c->name, name) == 0) | 215 | if (strcmp(c->name, name) == 0) |
215 | return c; | 216 | return c; |
216 | return NULL; | 217 | return NULL; |
217 | } | 218 | } |
218 | 219 | ||
219 | const Cipher * | 220 | const struct sshcipher * |
220 | cipher_by_number(int id) | 221 | cipher_by_number(int id) |
221 | { | 222 | { |
222 | const Cipher *c; | 223 | const struct sshcipher *c; |
223 | for (c = ciphers; c->name != NULL; c++) | 224 | for (c = ciphers; c->name != NULL; c++) |
224 | if (c->number == id) | 225 | if (c->number == id) |
225 | return c; | 226 | return c; |
@@ -230,23 +231,22 @@ cipher_by_number(int id) | |||
230 | int | 231 | int |
231 | ciphers_valid(const char *names) | 232 | ciphers_valid(const char *names) |
232 | { | 233 | { |
233 | const Cipher *c; | 234 | const struct sshcipher *c; |
234 | char *cipher_list, *cp; | 235 | char *cipher_list, *cp; |
235 | char *p; | 236 | char *p; |
236 | 237 | ||
237 | if (names == NULL || strcmp(names, "") == 0) | 238 | if (names == NULL || strcmp(names, "") == 0) |
238 | return 0; | 239 | return 0; |
239 | cipher_list = cp = xstrdup(names); | 240 | if ((cipher_list = cp = strdup(names)) == NULL) |
241 | return 0; | ||
240 | for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; | 242 | for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; |
241 | (p = strsep(&cp, CIPHER_SEP))) { | 243 | (p = strsep(&cp, CIPHER_SEP))) { |
242 | c = cipher_by_name(p); | 244 | c = cipher_by_name(p); |
243 | if (c == NULL || c->number != SSH_CIPHER_SSH2) { | 245 | if (c == NULL || c->number != SSH_CIPHER_SSH2) { |
244 | debug("bad cipher %s [%s]", p, names); | ||
245 | free(cipher_list); | 246 | free(cipher_list); |
246 | return 0; | 247 | return 0; |
247 | } | 248 | } |
248 | } | 249 | } |
249 | debug3("ciphers ok: [%s]", names); | ||
250 | free(cipher_list); | 250 | free(cipher_list); |
251 | return 1; | 251 | return 1; |
252 | } | 252 | } |
@@ -259,7 +259,7 @@ ciphers_valid(const char *names) | |||
259 | int | 259 | int |
260 | cipher_number(const char *name) | 260 | cipher_number(const char *name) |
261 | { | 261 | { |
262 | const Cipher *c; | 262 | const struct sshcipher *c; |
263 | if (name == NULL) | 263 | if (name == NULL) |
264 | return -1; | 264 | return -1; |
265 | for (c = ciphers; c->name != NULL; c++) | 265 | for (c = ciphers; c->name != NULL; c++) |
@@ -271,31 +271,33 @@ cipher_number(const char *name) | |||
271 | char * | 271 | char * |
272 | cipher_name(int id) | 272 | cipher_name(int id) |
273 | { | 273 | { |
274 | const Cipher *c = cipher_by_number(id); | 274 | const struct sshcipher *c = cipher_by_number(id); |
275 | return (c==NULL) ? "<unknown>" : c->name; | 275 | return (c==NULL) ? "<unknown>" : c->name; |
276 | } | 276 | } |
277 | 277 | ||
278 | void | 278 | const char * |
279 | cipher_init(CipherContext *cc, const Cipher *cipher, | 279 | cipher_warning_message(const struct sshcipher_ctx *cc) |
280 | { | ||
281 | if (cc == NULL || cc->cipher == NULL) | ||
282 | return NULL; | ||
283 | if (cc->cipher->number == SSH_CIPHER_DES) | ||
284 | return "use of DES is strongly discouraged due to " | ||
285 | "cryptographic weaknesses"; | ||
286 | return NULL; | ||
287 | } | ||
288 | |||
289 | int | ||
290 | cipher_init(struct sshcipher_ctx *cc, const struct sshcipher *cipher, | ||
280 | const u_char *key, u_int keylen, const u_char *iv, u_int ivlen, | 291 | const u_char *key, u_int keylen, const u_char *iv, u_int ivlen, |
281 | int do_encrypt) | 292 | int do_encrypt) |
282 | { | 293 | { |
283 | #ifdef WITH_OPENSSL | 294 | #ifdef WITH_OPENSSL |
284 | static int dowarn = 1; | 295 | int ret = SSH_ERR_INTERNAL_ERROR; |
285 | #ifdef SSH_OLD_EVP | ||
286 | EVP_CIPHER *type; | ||
287 | #else | ||
288 | const EVP_CIPHER *type; | 296 | const EVP_CIPHER *type; |
289 | int klen; | 297 | int klen; |
290 | #endif | ||
291 | u_char *junk, *discard; | 298 | u_char *junk, *discard; |
292 | 299 | ||
293 | if (cipher->number == SSH_CIPHER_DES) { | 300 | if (cipher->number == SSH_CIPHER_DES) { |
294 | if (dowarn) { | ||
295 | error("Warning: use of DES is strongly discouraged " | ||
296 | "due to cryptographic weaknesses"); | ||
297 | dowarn = 0; | ||
298 | } | ||
299 | if (keylen > 8) | 301 | if (keylen > 8) |
300 | keylen = 8; | 302 | keylen = 8; |
301 | } | 303 | } |
@@ -303,71 +305,70 @@ cipher_init(CipherContext *cc, const Cipher *cipher, | |||
303 | cc->plaintext = (cipher->number == SSH_CIPHER_NONE); | 305 | cc->plaintext = (cipher->number == SSH_CIPHER_NONE); |
304 | cc->encrypt = do_encrypt; | 306 | cc->encrypt = do_encrypt; |
305 | 307 | ||
306 | if (keylen < cipher->key_len) | 308 | if (keylen < cipher->key_len || |
307 | fatal("cipher_init: key length %d is insufficient for %s.", | 309 | (iv != NULL && ivlen < cipher_ivlen(cipher))) |
308 | keylen, cipher->name); | 310 | return SSH_ERR_INVALID_ARGUMENT; |
309 | if (iv != NULL && ivlen < cipher_ivlen(cipher)) | ||
310 | fatal("cipher_init: iv length %d is insufficient for %s.", | ||
311 | ivlen, cipher->name); | ||
312 | cc->cipher = cipher; | ||
313 | 311 | ||
312 | cc->cipher = cipher; | ||
314 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { | 313 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { |
315 | chachapoly_init(&cc->cp_ctx, key, keylen); | 314 | return chachapoly_init(&cc->cp_ctx, key, keylen); |
316 | return; | ||
317 | } | 315 | } |
318 | #ifndef WITH_OPENSSL | 316 | #ifndef WITH_OPENSSL |
319 | if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { | 317 | if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { |
320 | aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen); | 318 | aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen); |
321 | aesctr_ivsetup(&cc->ac_ctx, iv); | 319 | aesctr_ivsetup(&cc->ac_ctx, iv); |
322 | return; | 320 | return 0; |
323 | } | 321 | } |
324 | if ((cc->cipher->flags & CFLAG_NONE) != 0) | 322 | if ((cc->cipher->flags & CFLAG_NONE) != 0) |
325 | return; | 323 | return 0; |
326 | fatal("unsupported cipher"); | 324 | return SSH_ERR_INVALID_ARGUMENT; |
327 | #else | 325 | #else |
328 | type = (*cipher->evptype)(); | 326 | type = (*cipher->evptype)(); |
329 | EVP_CIPHER_CTX_init(&cc->evp); | 327 | EVP_CIPHER_CTX_init(&cc->evp); |
330 | #ifdef SSH_OLD_EVP | ||
331 | if (type->key_len > 0 && type->key_len != keylen) { | ||
332 | debug("cipher_init: set keylen (%d -> %d)", | ||
333 | type->key_len, keylen); | ||
334 | type->key_len = keylen; | ||
335 | } | ||
336 | EVP_CipherInit(&cc->evp, type, (u_char *)key, (u_char *)iv, | ||
337 | (do_encrypt == CIPHER_ENCRYPT)); | ||
338 | #else | ||
339 | if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv, | 328 | if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv, |
340 | (do_encrypt == CIPHER_ENCRYPT)) == 0) | 329 | (do_encrypt == CIPHER_ENCRYPT)) == 0) { |
341 | fatal("cipher_init: EVP_CipherInit failed for %s", | 330 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
342 | cipher->name); | 331 | goto bad; |
332 | } | ||
343 | if (cipher_authlen(cipher) && | 333 | if (cipher_authlen(cipher) && |
344 | !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_IV_FIXED, | 334 | !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_IV_FIXED, |
345 | -1, (u_char *)iv)) | 335 | -1, (u_char *)iv)) { |
346 | fatal("cipher_init: EVP_CTRL_GCM_SET_IV_FIXED failed for %s", | 336 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
347 | cipher->name); | 337 | goto bad; |
338 | } | ||
348 | klen = EVP_CIPHER_CTX_key_length(&cc->evp); | 339 | klen = EVP_CIPHER_CTX_key_length(&cc->evp); |
349 | if (klen > 0 && keylen != (u_int)klen) { | 340 | if (klen > 0 && keylen != (u_int)klen) { |
350 | debug2("cipher_init: set keylen (%d -> %d)", klen, keylen); | 341 | if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0) { |
351 | if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0) | 342 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
352 | fatal("cipher_init: set keylen failed (%d -> %d)", | 343 | goto bad; |
353 | klen, keylen); | 344 | } |
345 | } | ||
346 | if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0) { | ||
347 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
348 | goto bad; | ||
354 | } | 349 | } |
355 | if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0) | ||
356 | fatal("cipher_init: EVP_CipherInit: set key failed for %s", | ||
357 | cipher->name); | ||
358 | #endif | ||
359 | 350 | ||
360 | if (cipher->discard_len > 0) { | 351 | if (cipher->discard_len > 0) { |
361 | junk = xmalloc(cipher->discard_len); | 352 | if ((junk = malloc(cipher->discard_len)) == NULL || |
362 | discard = xmalloc(cipher->discard_len); | 353 | (discard = malloc(cipher->discard_len)) == NULL) { |
363 | if (EVP_Cipher(&cc->evp, discard, junk, | 354 | if (junk != NULL) |
364 | cipher->discard_len) == 0) | 355 | free(junk); |
365 | fatal("evp_crypt: EVP_Cipher failed during discard"); | 356 | ret = SSH_ERR_ALLOC_FAIL; |
357 | goto bad; | ||
358 | } | ||
359 | ret = EVP_Cipher(&cc->evp, discard, junk, cipher->discard_len); | ||
366 | explicit_bzero(discard, cipher->discard_len); | 360 | explicit_bzero(discard, cipher->discard_len); |
367 | free(junk); | 361 | free(junk); |
368 | free(discard); | 362 | free(discard); |
363 | if (ret != 1) { | ||
364 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
365 | bad: | ||
366 | EVP_CIPHER_CTX_cleanup(&cc->evp); | ||
367 | return ret; | ||
368 | } | ||
369 | } | 369 | } |
370 | #endif | 370 | #endif |
371 | return 0; | ||
371 | } | 372 | } |
372 | 373 | ||
373 | /* | 374 | /* |
@@ -379,16 +380,15 @@ cipher_init(CipherContext *cc, const Cipher *cipher, | |||
379 | * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag. | 380 | * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag. |
380 | * This tag is written on encryption and verified on decryption. | 381 | * This tag is written on encryption and verified on decryption. |
381 | * Both 'aadlen' and 'authlen' can be set to 0. | 382 | * Both 'aadlen' and 'authlen' can be set to 0. |
382 | * cipher_crypt() returns 0 on success and -1 if the decryption integrity | ||
383 | * check fails. | ||
384 | */ | 383 | */ |
385 | int | 384 | int |
386 | cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, | 385 | cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest, |
387 | u_int len, u_int aadlen, u_int authlen) | 386 | const u_char *src, u_int len, u_int aadlen, u_int authlen) |
388 | { | 387 | { |
389 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) | 388 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { |
390 | return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, len, | 389 | return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, |
391 | aadlen, authlen, cc->encrypt); | 390 | len, aadlen, authlen, cc->encrypt); |
391 | } | ||
392 | #ifndef WITH_OPENSSL | 392 | #ifndef WITH_OPENSSL |
393 | if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { | 393 | if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { |
394 | if (aadlen) | 394 | if (aadlen) |
@@ -401,46 +401,43 @@ cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, | |||
401 | memcpy(dest, src, aadlen + len); | 401 | memcpy(dest, src, aadlen + len); |
402 | return 0; | 402 | return 0; |
403 | } | 403 | } |
404 | fatal("unsupported cipher"); | 404 | return SSH_ERR_INVALID_ARGUMENT; |
405 | #else | 405 | #else |
406 | if (authlen) { | 406 | if (authlen) { |
407 | u_char lastiv[1]; | 407 | u_char lastiv[1]; |
408 | 408 | ||
409 | if (authlen != cipher_authlen(cc->cipher)) | 409 | if (authlen != cipher_authlen(cc->cipher)) |
410 | fatal("%s: authlen mismatch %d", __func__, authlen); | 410 | return SSH_ERR_INVALID_ARGUMENT; |
411 | /* increment IV */ | 411 | /* increment IV */ |
412 | if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN, | 412 | if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN, |
413 | 1, lastiv)) | 413 | 1, lastiv)) |
414 | fatal("%s: EVP_CTRL_GCM_IV_GEN", __func__); | 414 | return SSH_ERR_LIBCRYPTO_ERROR; |
415 | /* set tag on decyption */ | 415 | /* set tag on decyption */ |
416 | if (!cc->encrypt && | 416 | if (!cc->encrypt && |
417 | !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_TAG, | 417 | !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_TAG, |
418 | authlen, (u_char *)src + aadlen + len)) | 418 | authlen, (u_char *)src + aadlen + len)) |
419 | fatal("%s: EVP_CTRL_GCM_SET_TAG", __func__); | 419 | return SSH_ERR_LIBCRYPTO_ERROR; |
420 | } | 420 | } |
421 | if (aadlen) { | 421 | if (aadlen) { |
422 | if (authlen && | 422 | if (authlen && |
423 | EVP_Cipher(&cc->evp, NULL, (u_char *)src, aadlen) < 0) | 423 | EVP_Cipher(&cc->evp, NULL, (u_char *)src, aadlen) < 0) |
424 | fatal("%s: EVP_Cipher(aad) failed", __func__); | 424 | return SSH_ERR_LIBCRYPTO_ERROR; |
425 | memcpy(dest, src, aadlen); | 425 | memcpy(dest, src, aadlen); |
426 | } | 426 | } |
427 | if (len % cc->cipher->block_size) | 427 | if (len % cc->cipher->block_size) |
428 | fatal("%s: bad plaintext length %d", __func__, len); | 428 | return SSH_ERR_INVALID_ARGUMENT; |
429 | if (EVP_Cipher(&cc->evp, dest + aadlen, (u_char *)src + aadlen, | 429 | if (EVP_Cipher(&cc->evp, dest + aadlen, (u_char *)src + aadlen, |
430 | len) < 0) | 430 | len) < 0) |
431 | fatal("%s: EVP_Cipher failed", __func__); | 431 | return SSH_ERR_LIBCRYPTO_ERROR; |
432 | if (authlen) { | 432 | if (authlen) { |
433 | /* compute tag (on encrypt) or verify tag (on decrypt) */ | 433 | /* compute tag (on encrypt) or verify tag (on decrypt) */ |
434 | if (EVP_Cipher(&cc->evp, NULL, NULL, 0) < 0) { | 434 | if (EVP_Cipher(&cc->evp, NULL, NULL, 0) < 0) |
435 | if (cc->encrypt) | 435 | return cc->encrypt ? |
436 | fatal("%s: EVP_Cipher(final) failed", __func__); | 436 | SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID; |
437 | else | ||
438 | return -1; | ||
439 | } | ||
440 | if (cc->encrypt && | 437 | if (cc->encrypt && |
441 | !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG, | 438 | !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG, |
442 | authlen, dest + aadlen + len)) | 439 | authlen, dest + aadlen + len)) |
443 | fatal("%s: EVP_CTRL_GCM_GET_TAG", __func__); | 440 | return SSH_ERR_LIBCRYPTO_ERROR; |
444 | } | 441 | } |
445 | return 0; | 442 | return 0; |
446 | #endif | 443 | #endif |
@@ -448,61 +445,65 @@ cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, | |||
448 | 445 | ||
449 | /* Extract the packet length, including any decryption necessary beforehand */ | 446 | /* Extract the packet length, including any decryption necessary beforehand */ |
450 | int | 447 | int |
451 | cipher_get_length(CipherContext *cc, u_int *plenp, u_int seqnr, | 448 | cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr, |
452 | const u_char *cp, u_int len) | 449 | const u_char *cp, u_int len) |
453 | { | 450 | { |
454 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) | 451 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) |
455 | return chachapoly_get_length(&cc->cp_ctx, plenp, seqnr, | 452 | return chachapoly_get_length(&cc->cp_ctx, plenp, seqnr, |
456 | cp, len); | 453 | cp, len); |
457 | if (len < 4) | 454 | if (len < 4) |
458 | return -1; | 455 | return SSH_ERR_MESSAGE_INCOMPLETE; |
459 | *plenp = get_u32(cp); | 456 | *plenp = get_u32(cp); |
460 | return 0; | 457 | return 0; |
461 | } | 458 | } |
462 | 459 | ||
463 | void | 460 | int |
464 | cipher_cleanup(CipherContext *cc) | 461 | cipher_cleanup(struct sshcipher_ctx *cc) |
465 | { | 462 | { |
463 | if (cc == NULL || cc->cipher == NULL) | ||
464 | return 0; | ||
466 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) | 465 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) |
467 | explicit_bzero(&cc->cp_ctx, sizeof(cc->cp_ctx)); | 466 | explicit_bzero(&cc->cp_ctx, sizeof(cc->cp_ctx)); |
468 | else if ((cc->cipher->flags & CFLAG_AESCTR) != 0) | 467 | else if ((cc->cipher->flags & CFLAG_AESCTR) != 0) |
469 | explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx)); | 468 | explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx)); |
470 | #ifdef WITH_OPENSSL | 469 | #ifdef WITH_OPENSSL |
471 | else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) | 470 | else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) |
472 | error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); | 471 | return SSH_ERR_LIBCRYPTO_ERROR; |
473 | #endif | 472 | #endif |
473 | return 0; | ||
474 | } | 474 | } |
475 | 475 | ||
476 | /* | 476 | /* |
477 | * Selects the cipher, and keys if by computing the MD5 checksum of the | 477 | * Selects the cipher, and keys if by computing the MD5 checksum of the |
478 | * passphrase and using the resulting 16 bytes as the key. | 478 | * passphrase and using the resulting 16 bytes as the key. |
479 | */ | 479 | */ |
480 | 480 | int | |
481 | void | 481 | cipher_set_key_string(struct sshcipher_ctx *cc, const struct sshcipher *cipher, |
482 | cipher_set_key_string(CipherContext *cc, const Cipher *cipher, | ||
483 | const char *passphrase, int do_encrypt) | 482 | const char *passphrase, int do_encrypt) |
484 | { | 483 | { |
485 | u_char digest[16]; | 484 | u_char digest[16]; |
485 | int r = SSH_ERR_INTERNAL_ERROR; | ||
486 | 486 | ||
487 | if (ssh_digest_memory(SSH_DIGEST_MD5, passphrase, strlen(passphrase), | 487 | if ((r = ssh_digest_memory(SSH_DIGEST_MD5, |
488 | digest, sizeof(digest)) < 0) | 488 | passphrase, strlen(passphrase), |
489 | fatal("%s: md5 failed", __func__); | 489 | digest, sizeof(digest))) != 0) |
490 | 490 | goto out; | |
491 | cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt); | ||
492 | 491 | ||
492 | r = cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt); | ||
493 | out: | ||
493 | explicit_bzero(digest, sizeof(digest)); | 494 | explicit_bzero(digest, sizeof(digest)); |
495 | return r; | ||
494 | } | 496 | } |
495 | 497 | ||
496 | /* | 498 | /* |
497 | * Exports an IV from the CipherContext required to export the key | 499 | * Exports an IV from the sshcipher_ctx required to export the key |
498 | * state back from the unprivileged child to the privileged parent | 500 | * state back from the unprivileged child to the privileged parent |
499 | * process. | 501 | * process. |
500 | */ | 502 | */ |
501 | |||
502 | int | 503 | int |
503 | cipher_get_keyiv_len(const CipherContext *cc) | 504 | cipher_get_keyiv_len(const struct sshcipher_ctx *cc) |
504 | { | 505 | { |
505 | const Cipher *c = cc->cipher; | 506 | const struct sshcipher *c = cc->cipher; |
506 | int ivlen = 0; | 507 | int ivlen = 0; |
507 | 508 | ||
508 | if (c->number == SSH_CIPHER_3DES) | 509 | if (c->number == SSH_CIPHER_3DES) |
@@ -512,25 +513,25 @@ cipher_get_keyiv_len(const CipherContext *cc) | |||
512 | #ifdef WITH_OPENSSL | 513 | #ifdef WITH_OPENSSL |
513 | else | 514 | else |
514 | ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); | 515 | ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); |
515 | #endif | 516 | #endif /* WITH_OPENSSL */ |
516 | return (ivlen); | 517 | return (ivlen); |
517 | } | 518 | } |
518 | 519 | ||
519 | void | 520 | int |
520 | cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) | 521 | cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len) |
521 | { | 522 | { |
522 | const Cipher *c = cc->cipher; | 523 | const struct sshcipher *c = cc->cipher; |
523 | #ifdef WITH_OPENSSL | 524 | #ifdef WITH_OPENSSL |
524 | int evplen; | 525 | int evplen; |
525 | #endif | 526 | #endif |
526 | 527 | ||
527 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { | 528 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { |
528 | if (len != 0) | 529 | if (len != 0) |
529 | fatal("%s: wrong iv length %d != %d", __func__, len, 0); | 530 | return SSH_ERR_INVALID_ARGUMENT; |
530 | return; | 531 | return 0; |
531 | } | 532 | } |
532 | if ((cc->cipher->flags & CFLAG_NONE) != 0) | 533 | if ((cc->cipher->flags & CFLAG_NONE) != 0) |
533 | return; | 534 | return 0; |
534 | 535 | ||
535 | switch (c->number) { | 536 | switch (c->number) { |
536 | #ifdef WITH_OPENSSL | 537 | #ifdef WITH_OPENSSL |
@@ -538,51 +539,42 @@ cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) | |||
538 | case SSH_CIPHER_DES: | 539 | case SSH_CIPHER_DES: |
539 | case SSH_CIPHER_BLOWFISH: | 540 | case SSH_CIPHER_BLOWFISH: |
540 | evplen = EVP_CIPHER_CTX_iv_length(&cc->evp); | 541 | evplen = EVP_CIPHER_CTX_iv_length(&cc->evp); |
541 | if (evplen <= 0) | 542 | if (evplen == 0) |
542 | return; | 543 | return 0; |
544 | else if (evplen < 0) | ||
545 | return SSH_ERR_LIBCRYPTO_ERROR; | ||
543 | if ((u_int)evplen != len) | 546 | if ((u_int)evplen != len) |
544 | fatal("%s: wrong iv length %d != %d", __func__, | 547 | return SSH_ERR_INVALID_ARGUMENT; |
545 | evplen, len); | ||
546 | #ifdef USE_BUILTIN_RIJNDAEL | ||
547 | if (c->evptype == evp_rijndael) | ||
548 | ssh_rijndael_iv(&cc->evp, 0, iv, len); | ||
549 | else | ||
550 | #endif /* USE_BUILTIN_RIJNDAEL */ | ||
551 | #ifndef OPENSSL_HAVE_EVPCTR | ||
552 | if (c->evptype == evp_aes_128_ctr) | ||
553 | ssh_aes_ctr_iv(&cc->evp, 0, iv, len); | ||
554 | else | ||
555 | #endif /* OPENSSL_HAVE_EVPCTR */ | ||
556 | if (cipher_authlen(c)) { | 548 | if (cipher_authlen(c)) { |
557 | if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN, | 549 | if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN, |
558 | len, iv)) | 550 | len, iv)) |
559 | fatal("%s: EVP_CTRL_GCM_IV_GEN", __func__); | 551 | return SSH_ERR_LIBCRYPTO_ERROR; |
560 | } else | 552 | } else |
561 | memcpy(iv, cc->evp.iv, len); | 553 | memcpy(iv, cc->evp.iv, len); |
562 | break; | 554 | break; |
563 | #endif /* WITH_OPENSSL */ | 555 | #endif |
564 | #ifdef WITH_SSH1 | 556 | #ifdef WITH_SSH1 |
565 | case SSH_CIPHER_3DES: | 557 | case SSH_CIPHER_3DES: |
566 | ssh1_3des_iv(&cc->evp, 0, iv, 24); | 558 | return ssh1_3des_iv(&cc->evp, 0, iv, 24); |
567 | break; | 559 | #endif |
568 | #endif /* WITH_SSH1 */ | ||
569 | default: | 560 | default: |
570 | fatal("%s: bad cipher %d", __func__, c->number); | 561 | return SSH_ERR_INVALID_ARGUMENT; |
571 | } | 562 | } |
563 | return 0; | ||
572 | } | 564 | } |
573 | 565 | ||
574 | void | 566 | int |
575 | cipher_set_keyiv(CipherContext *cc, u_char *iv) | 567 | cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv) |
576 | { | 568 | { |
577 | const Cipher *c = cc->cipher; | 569 | const struct sshcipher *c = cc->cipher; |
578 | #ifdef WITH_OPENSSL | 570 | #ifdef WITH_OPENSSL |
579 | int evplen = 0; | 571 | int evplen = 0; |
580 | #endif | 572 | #endif |
581 | 573 | ||
582 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) | 574 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) |
583 | return; | 575 | return 0; |
584 | if ((cc->cipher->flags & CFLAG_NONE) != 0) | 576 | if ((cc->cipher->flags & CFLAG_NONE) != 0) |
585 | return; | 577 | return 0; |
586 | 578 | ||
587 | switch (c->number) { | 579 | switch (c->number) { |
588 | #ifdef WITH_OPENSSL | 580 | #ifdef WITH_OPENSSL |
@@ -590,42 +582,37 @@ cipher_set_keyiv(CipherContext *cc, u_char *iv) | |||
590 | case SSH_CIPHER_DES: | 582 | case SSH_CIPHER_DES: |
591 | case SSH_CIPHER_BLOWFISH: | 583 | case SSH_CIPHER_BLOWFISH: |
592 | evplen = EVP_CIPHER_CTX_iv_length(&cc->evp); | 584 | evplen = EVP_CIPHER_CTX_iv_length(&cc->evp); |
593 | if (evplen == 0) | 585 | if (evplen <= 0) |
594 | return; | 586 | return SSH_ERR_LIBCRYPTO_ERROR; |
595 | #ifdef USE_BUILTIN_RIJNDAEL | ||
596 | if (c->evptype == evp_rijndael) | ||
597 | ssh_rijndael_iv(&cc->evp, 1, iv, evplen); | ||
598 | else | ||
599 | #endif /* USE_BUILTIN_RIJNDAEL */ | ||
600 | #ifndef OPENSSL_HAVE_EVPCTR | ||
601 | if (c->evptype == evp_aes_128_ctr) | ||
602 | ssh_aes_ctr_iv(&cc->evp, 1, iv, evplen); | ||
603 | else | ||
604 | #endif /* OPENSSL_HAVE_EVPCTR */ | ||
605 | if (cipher_authlen(c)) { | 587 | if (cipher_authlen(c)) { |
588 | /* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */ | ||
606 | if (!EVP_CIPHER_CTX_ctrl(&cc->evp, | 589 | if (!EVP_CIPHER_CTX_ctrl(&cc->evp, |
607 | EVP_CTRL_GCM_SET_IV_FIXED, -1, iv)) | 590 | EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv)) |
608 | fatal("%s: EVP_CTRL_GCM_SET_IV_FIXED failed", | 591 | return SSH_ERR_LIBCRYPTO_ERROR; |
609 | __func__); | 592 | } else |
610 | } else | 593 | memcpy(cc->evp.iv, iv, evplen); |
611 | memcpy(cc->evp.iv, iv, evplen); | ||
612 | break; | 594 | break; |
613 | #endif /* WITH_OPENSSL */ | 595 | #endif |
614 | #ifdef WITH_SSH1 | 596 | #ifdef WITH_SSH1 |
615 | case SSH_CIPHER_3DES: | 597 | case SSH_CIPHER_3DES: |
616 | ssh1_3des_iv(&cc->evp, 1, iv, 24); | 598 | return ssh1_3des_iv(&cc->evp, 1, (u_char *)iv, 24); |
617 | break; | 599 | #endif |
618 | #endif /* WITH_SSH1 */ | ||
619 | default: | 600 | default: |
620 | fatal("%s: bad cipher %d", __func__, c->number); | 601 | return SSH_ERR_INVALID_ARGUMENT; |
621 | } | 602 | } |
603 | return 0; | ||
622 | } | 604 | } |
623 | 605 | ||
606 | #ifdef WITH_OPENSSL | ||
607 | #define EVP_X_STATE(evp) (evp).cipher_data | ||
608 | #define EVP_X_STATE_LEN(evp) (evp).cipher->ctx_size | ||
609 | #endif | ||
610 | |||
624 | int | 611 | int |
625 | cipher_get_keycontext(const CipherContext *cc, u_char *dat) | 612 | cipher_get_keycontext(const struct sshcipher_ctx *cc, u_char *dat) |
626 | { | 613 | { |
627 | #ifdef WITH_OPENSSL | 614 | #ifdef WITH_OPENSSL |
628 | const Cipher *c = cc->cipher; | 615 | const struct sshcipher *c = cc->cipher; |
629 | int plen = 0; | 616 | int plen = 0; |
630 | 617 | ||
631 | if (c->evptype == EVP_rc4) { | 618 | if (c->evptype == EVP_rc4) { |
@@ -636,15 +623,15 @@ cipher_get_keycontext(const CipherContext *cc, u_char *dat) | |||
636 | } | 623 | } |
637 | return (plen); | 624 | return (plen); |
638 | #else | 625 | #else |
639 | return (0); | 626 | return 0; |
640 | #endif | 627 | #endif |
641 | } | 628 | } |
642 | 629 | ||
643 | void | 630 | void |
644 | cipher_set_keycontext(CipherContext *cc, u_char *dat) | 631 | cipher_set_keycontext(struct sshcipher_ctx *cc, const u_char *dat) |
645 | { | 632 | { |
646 | #ifdef WITH_OPENSSL | 633 | #ifdef WITH_OPENSSL |
647 | const Cipher *c = cc->cipher; | 634 | const struct sshcipher *c = cc->cipher; |
648 | int plen; | 635 | int plen; |
649 | 636 | ||
650 | if (c->evptype == EVP_rc4) { | 637 | if (c->evptype == EVP_rc4) { |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: cipher.h,v 1.45 2014/04/29 18:01:49 markus Exp $ */ | 1 | /* $OpenBSD: cipher.h,v 1.46 2014/06/24 01:13:21 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -37,6 +37,7 @@ | |||
37 | #ifndef CIPHER_H | 37 | #ifndef CIPHER_H |
38 | #define CIPHER_H | 38 | #define CIPHER_H |
39 | 39 | ||
40 | #include <sys/types.h> | ||
40 | #include <openssl/evp.h> | 41 | #include <openssl/evp.h> |
41 | #include "cipher-chachapoly.h" | 42 | #include "cipher-chachapoly.h" |
42 | #include "cipher-aesctr.h" | 43 | #include "cipher-aesctr.h" |
@@ -61,45 +62,47 @@ | |||
61 | #define CIPHER_ENCRYPT 1 | 62 | #define CIPHER_ENCRYPT 1 |
62 | #define CIPHER_DECRYPT 0 | 63 | #define CIPHER_DECRYPT 0 |
63 | 64 | ||
64 | typedef struct Cipher Cipher; | 65 | struct sshcipher; |
65 | typedef struct CipherContext CipherContext; | 66 | struct sshcipher_ctx { |
66 | |||
67 | struct Cipher; | ||
68 | struct CipherContext { | ||
69 | int plaintext; | 67 | int plaintext; |
70 | int encrypt; | 68 | int encrypt; |
71 | EVP_CIPHER_CTX evp; | 69 | EVP_CIPHER_CTX evp; |
72 | struct chachapoly_ctx cp_ctx; /* XXX union with evp? */ | 70 | struct chachapoly_ctx cp_ctx; /* XXX union with evp? */ |
73 | struct aesctr_ctx ac_ctx; /* XXX union with evp? */ | 71 | struct aesctr_ctx ac_ctx; /* XXX union with evp? */ |
74 | const Cipher *cipher; | 72 | const struct sshcipher *cipher; |
75 | }; | 73 | }; |
76 | 74 | ||
75 | typedef struct sshcipher Cipher ; | ||
76 | typedef struct sshcipher_ctx CipherContext ; | ||
77 | |||
77 | u_int cipher_mask_ssh1(int); | 78 | u_int cipher_mask_ssh1(int); |
78 | const Cipher *cipher_by_name(const char *); | 79 | const struct sshcipher *cipher_by_name(const char *); |
79 | const Cipher *cipher_by_number(int); | 80 | const struct sshcipher *cipher_by_number(int); |
80 | int cipher_number(const char *); | 81 | int cipher_number(const char *); |
81 | char *cipher_name(int); | 82 | char *cipher_name(int); |
82 | int ciphers_valid(const char *); | 83 | int ciphers_valid(const char *); |
83 | char *cipher_alg_list(char, int); | 84 | char *cipher_alg_list(char, int); |
84 | void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int, | 85 | int cipher_init(struct sshcipher_ctx *, const struct sshcipher *, |
85 | const u_char *, u_int, int); | 86 | const u_char *, u_int, const u_char *, u_int, int); |
86 | int cipher_crypt(CipherContext *, u_int, u_char *, const u_char *, | 87 | const char* cipher_warning_message(const struct sshcipher_ctx *); |
88 | int cipher_crypt(struct sshcipher_ctx *, u_int, u_char *, const u_char *, | ||
87 | u_int, u_int, u_int); | 89 | u_int, u_int, u_int); |
88 | int cipher_get_length(CipherContext *, u_int *, u_int, | 90 | int cipher_get_length(struct sshcipher_ctx *, u_int *, u_int, |
89 | const u_char *, u_int); | 91 | const u_char *, u_int); |
90 | void cipher_cleanup(CipherContext *); | 92 | int cipher_cleanup(struct sshcipher_ctx *); |
91 | void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int); | 93 | int cipher_set_key_string(struct sshcipher_ctx *, const struct sshcipher *, |
92 | u_int cipher_blocksize(const Cipher *); | 94 | const char *, int); |
93 | u_int cipher_keylen(const Cipher *); | 95 | u_int cipher_blocksize(const struct sshcipher *); |
94 | u_int cipher_seclen(const Cipher *); | 96 | u_int cipher_keylen(const struct sshcipher *); |
95 | u_int cipher_authlen(const Cipher *); | 97 | u_int cipher_seclen(const struct sshcipher *); |
96 | u_int cipher_ivlen(const Cipher *); | 98 | u_int cipher_authlen(const struct sshcipher *); |
97 | u_int cipher_is_cbc(const Cipher *); | 99 | u_int cipher_ivlen(const struct sshcipher *); |
100 | u_int cipher_is_cbc(const struct sshcipher *); | ||
98 | 101 | ||
99 | u_int cipher_get_number(const Cipher *); | 102 | u_int cipher_get_number(const struct sshcipher *); |
100 | void cipher_get_keyiv(CipherContext *, u_char *, u_int); | 103 | int cipher_get_keyiv(struct sshcipher_ctx *, u_char *, u_int); |
101 | void cipher_set_keyiv(CipherContext *, u_char *); | 104 | int cipher_set_keyiv(struct sshcipher_ctx *, const u_char *); |
102 | int cipher_get_keyiv_len(const CipherContext *); | 105 | int cipher_get_keyiv_len(const struct sshcipher_ctx *); |
103 | int cipher_get_keycontext(const CipherContext *, u_char *); | 106 | int cipher_get_keycontext(const struct sshcipher_ctx *, u_char *); |
104 | void cipher_set_keycontext(CipherContext *, u_char *); | 107 | void cipher_set_keycontext(struct sshcipher_ctx *, const u_char *); |
105 | #endif /* CIPHER_H */ | 108 | #endif /* CIPHER_H */ |
diff --git a/digest-libc.c b/digest-libc.c index 1804b0698..1b4423a05 100644 --- a/digest-libc.c +++ b/digest-libc.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: digest-libc.c,v 1.2 2014/02/02 03:44:31 djm Exp $ */ | 1 | /* $OpenBSD: digest-libc.c,v 1.3 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2013 Damien Miller <djm@mindrot.org> | 3 | * Copyright (c) 2013 Damien Miller <djm@mindrot.org> |
4 | * Copyright (c) 2014 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2014 Markus Friedl. All rights reserved. |
@@ -28,7 +28,8 @@ | |||
28 | #include <sha1.h> | 28 | #include <sha1.h> |
29 | #include <sha2.h> | 29 | #include <sha2.h> |
30 | 30 | ||
31 | #include "buffer.h" | 31 | #include "ssherr.h" |
32 | #include "sshbuf.h" | ||
32 | #include "digest.h" | 33 | #include "digest.h" |
33 | 34 | ||
34 | typedef void md_init_fn(void *mdctx); | 35 | typedef void md_init_fn(void *mdctx); |
@@ -164,7 +165,7 @@ ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to) | |||
164 | const struct ssh_digest *digest = ssh_digest_by_alg(from->alg); | 165 | const struct ssh_digest *digest = ssh_digest_by_alg(from->alg); |
165 | 166 | ||
166 | if (digest == NULL || from->alg != to->alg) | 167 | if (digest == NULL || from->alg != to->alg) |
167 | return -1; | 168 | return SSH_ERR_INVALID_ARGUMENT; |
168 | memcpy(to->mdctx, from->mdctx, digest->ctx_len); | 169 | memcpy(to->mdctx, from->mdctx, digest->ctx_len); |
169 | return 0; | 170 | return 0; |
170 | } | 171 | } |
@@ -175,15 +176,15 @@ ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) | |||
175 | const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); | 176 | const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); |
176 | 177 | ||
177 | if (digest == NULL) | 178 | if (digest == NULL) |
178 | return -1; | 179 | return SSH_ERR_INVALID_ARGUMENT; |
179 | digest->md_update(ctx->mdctx, m, mlen); | 180 | digest->md_update(ctx->mdctx, m, mlen); |
180 | return 0; | 181 | return 0; |
181 | } | 182 | } |
182 | 183 | ||
183 | int | 184 | int |
184 | ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b) | 185 | ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const struct sshbuf *b) |
185 | { | 186 | { |
186 | return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b)); | 187 | return ssh_digest_update(ctx, sshbuf_ptr(b), sshbuf_len(b)); |
187 | } | 188 | } |
188 | 189 | ||
189 | int | 190 | int |
@@ -192,11 +193,11 @@ ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) | |||
192 | const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); | 193 | const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); |
193 | 194 | ||
194 | if (digest == NULL) | 195 | if (digest == NULL) |
195 | return -1; | 196 | return SSH_ERR_INVALID_ARGUMENT; |
196 | if (dlen > UINT_MAX) | 197 | if (dlen > UINT_MAX) |
197 | return -1; | 198 | return SSH_ERR_INVALID_ARGUMENT; |
198 | if (dlen < digest->digest_len) /* No truncation allowed */ | 199 | if (dlen < digest->digest_len) /* No truncation allowed */ |
199 | return -1; | 200 | return SSH_ERR_INVALID_ARGUMENT; |
200 | digest->md_final(d, ctx->mdctx); | 201 | digest->md_final(d, ctx->mdctx); |
201 | return 0; | 202 | return 0; |
202 | } | 203 | } |
@@ -223,16 +224,16 @@ ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen) | |||
223 | struct ssh_digest_ctx *ctx = ssh_digest_start(alg); | 224 | struct ssh_digest_ctx *ctx = ssh_digest_start(alg); |
224 | 225 | ||
225 | if (ctx == NULL) | 226 | if (ctx == NULL) |
226 | return -1; | 227 | return SSH_ERR_INVALID_ARGUMENT; |
227 | if (ssh_digest_update(ctx, m, mlen) != 0 || | 228 | if (ssh_digest_update(ctx, m, mlen) != 0 || |
228 | ssh_digest_final(ctx, d, dlen) != 0) | 229 | ssh_digest_final(ctx, d, dlen) != 0) |
229 | return -1; | 230 | return SSH_ERR_INVALID_ARGUMENT; |
230 | ssh_digest_free(ctx); | 231 | ssh_digest_free(ctx); |
231 | return 0; | 232 | return 0; |
232 | } | 233 | } |
233 | 234 | ||
234 | int | 235 | int |
235 | ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen) | 236 | ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen) |
236 | { | 237 | { |
237 | return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen); | 238 | return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen); |
238 | } | 239 | } |
diff --git a/digest-openssl.c b/digest-openssl.c index 863d37d03..de0380135 100644 --- a/digest-openssl.c +++ b/digest-openssl.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: digest-openssl.c,v 1.2 2014/02/02 03:44:31 djm Exp $ */ | 1 | /* $OpenBSD: digest-openssl.c,v 1.3 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2013 Damien Miller <djm@mindrot.org> | 3 | * Copyright (c) 2013 Damien Miller <djm@mindrot.org> |
4 | * | 4 | * |
@@ -26,8 +26,9 @@ | |||
26 | 26 | ||
27 | #include "openbsd-compat/openssl-compat.h" | 27 | #include "openbsd-compat/openssl-compat.h" |
28 | 28 | ||
29 | #include "buffer.h" | 29 | #include "sshbuf.h" |
30 | #include "digest.h" | 30 | #include "digest.h" |
31 | #include "ssherr.h" | ||
31 | 32 | ||
32 | struct ssh_digest_ctx { | 33 | struct ssh_digest_ctx { |
33 | int alg; | 34 | int alg; |
@@ -98,9 +99,11 @@ ssh_digest_start(int alg) | |||
98 | int | 99 | int |
99 | ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to) | 100 | ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to) |
100 | { | 101 | { |
102 | if (from->alg != to->alg) | ||
103 | return SSH_ERR_INVALID_ARGUMENT; | ||
101 | /* we have bcopy-style order while openssl has memcpy-style */ | 104 | /* we have bcopy-style order while openssl has memcpy-style */ |
102 | if (!EVP_MD_CTX_copy_ex(&to->mdctx, &from->mdctx)) | 105 | if (!EVP_MD_CTX_copy_ex(&to->mdctx, &from->mdctx)) |
103 | return -1; | 106 | return SSH_ERR_LIBCRYPTO_ERROR; |
104 | return 0; | 107 | return 0; |
105 | } | 108 | } |
106 | 109 | ||
@@ -108,14 +111,14 @@ int | |||
108 | ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) | 111 | ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) |
109 | { | 112 | { |
110 | if (EVP_DigestUpdate(&ctx->mdctx, m, mlen) != 1) | 113 | if (EVP_DigestUpdate(&ctx->mdctx, m, mlen) != 1) |
111 | return -1; | 114 | return SSH_ERR_LIBCRYPTO_ERROR; |
112 | return 0; | 115 | return 0; |
113 | } | 116 | } |
114 | 117 | ||
115 | int | 118 | int |
116 | ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b) | 119 | ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const struct sshbuf *b) |
117 | { | 120 | { |
118 | return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b)); | 121 | return ssh_digest_update(ctx, sshbuf_ptr(b), sshbuf_len(b)); |
119 | } | 122 | } |
120 | 123 | ||
121 | int | 124 | int |
@@ -125,13 +128,13 @@ ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) | |||
125 | u_int l = dlen; | 128 | u_int l = dlen; |
126 | 129 | ||
127 | if (dlen > UINT_MAX) | 130 | if (dlen > UINT_MAX) |
128 | return -1; | 131 | return SSH_ERR_INVALID_ARGUMENT; |
129 | if (dlen < digest->digest_len) /* No truncation allowed */ | 132 | if (dlen < digest->digest_len) /* No truncation allowed */ |
130 | return -1; | 133 | return SSH_ERR_INVALID_ARGUMENT; |
131 | if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1) | 134 | if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1) |
132 | return -1; | 135 | return SSH_ERR_LIBCRYPTO_ERROR; |
133 | if (l != digest->digest_len) /* sanity */ | 136 | if (l != digest->digest_len) /* sanity */ |
134 | return -1; | 137 | return SSH_ERR_INTERNAL_ERROR; |
135 | return 0; | 138 | return 0; |
136 | } | 139 | } |
137 | 140 | ||
@@ -149,18 +152,19 @@ int | |||
149 | ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen) | 152 | ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen) |
150 | { | 153 | { |
151 | struct ssh_digest_ctx *ctx = ssh_digest_start(alg); | 154 | struct ssh_digest_ctx *ctx = ssh_digest_start(alg); |
155 | int r; | ||
152 | 156 | ||
153 | if (ctx == NULL) | 157 | if (ctx == NULL) |
154 | return -1; | 158 | return SSH_ERR_INVALID_ARGUMENT; |
155 | if (ssh_digest_update(ctx, m, mlen) != 0 || | 159 | if ((r = ssh_digest_update(ctx, m, mlen) != 0) || |
156 | ssh_digest_final(ctx, d, dlen) != 0) | 160 | (r = ssh_digest_final(ctx, d, dlen) != 0)) |
157 | return -1; | 161 | return r; |
158 | ssh_digest_free(ctx); | 162 | ssh_digest_free(ctx); |
159 | return 0; | 163 | return 0; |
160 | } | 164 | } |
161 | 165 | ||
162 | int | 166 | int |
163 | ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen) | 167 | ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen) |
164 | { | 168 | { |
165 | return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen); | 169 | return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen); |
166 | } | 170 | } |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: digest.h,v 1.4 2014/05/02 03:27:54 djm Exp $ */ | 1 | /* $OpenBSD: digest.h,v 1.5 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2013 Damien Miller <djm@mindrot.org> | 3 | * Copyright (c) 2013 Damien Miller <djm@mindrot.org> |
4 | * | 4 | * |
@@ -47,14 +47,15 @@ int ssh_digest_memory(int alg, const void *m, size_t mlen, | |||
47 | u_char *d, size_t dlen) | 47 | u_char *d, size_t dlen) |
48 | __attribute__((__bounded__(__buffer__, 2, 3))) | 48 | __attribute__((__bounded__(__buffer__, 2, 3))) |
49 | __attribute__((__bounded__(__buffer__, 4, 5))); | 49 | __attribute__((__bounded__(__buffer__, 4, 5))); |
50 | int ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen) | 50 | int ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen) |
51 | __attribute__((__bounded__(__buffer__, 3, 4))); | 51 | __attribute__((__bounded__(__buffer__, 3, 4))); |
52 | 52 | ||
53 | /* Update API */ | 53 | /* Update API */ |
54 | struct ssh_digest_ctx *ssh_digest_start(int alg); | 54 | struct ssh_digest_ctx *ssh_digest_start(int alg); |
55 | int ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) | 55 | int ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) |
56 | __attribute__((__bounded__(__buffer__, 2, 3))); | 56 | __attribute__((__bounded__(__buffer__, 2, 3))); |
57 | int ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b); | 57 | int ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, |
58 | const struct sshbuf *b); | ||
58 | int ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) | 59 | int ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) |
59 | __attribute__((__bounded__(__buffer__, 2, 3))); | 60 | __attribute__((__bounded__(__buffer__, 2, 3))); |
60 | void ssh_digest_free(struct ssh_digest_ctx *ctx); | 61 | void ssh_digest_free(struct ssh_digest_ctx *ctx); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: dns.c,v 1.30 2014/04/20 09:24:26 logan Exp $ */ | 1 | /* $OpenBSD: dns.c,v 1.31 2014/06/24 01:13:21 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2003 Wesley Griffin. All rights reserved. | 4 | * Copyright (c) 2003 Wesley Griffin. All rights reserved. |
@@ -34,6 +34,8 @@ | |||
34 | #include <stdarg.h> | 34 | #include <stdarg.h> |
35 | #include <stdio.h> | 35 | #include <stdio.h> |
36 | #include <string.h> | 36 | #include <string.h> |
37 | #include <stdarg.h> | ||
38 | #include <stdlib.h> | ||
37 | 39 | ||
38 | #include "xmalloc.h" | 40 | #include "xmalloc.h" |
39 | #include "key.h" | 41 | #include "key.h" |
@@ -43,6 +43,8 @@ | |||
43 | #include <openssl/crypto.h> | 43 | #include <openssl/crypto.h> |
44 | #include <openssl/err.h> | 44 | #include <openssl/err.h> |
45 | 45 | ||
46 | #include "openbsd-compat/openssl-compat.h" | ||
47 | |||
46 | #include "ssh.h" | 48 | #include "ssh.h" |
47 | #include "misc.h" | 49 | #include "misc.h" |
48 | #include "xmalloc.h" | 50 | #include "xmalloc.h" |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: hmac.h,v 1.8 2014/05/02 03:27:54 djm Exp $ */ | 1 | /* $OpenBSD: hmac.h,v 1.9 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2014 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2014 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -21,6 +21,7 @@ | |||
21 | /* Returns the algorithm's digest length in bytes or 0 for invalid algorithm */ | 21 | /* Returns the algorithm's digest length in bytes or 0 for invalid algorithm */ |
22 | size_t ssh_hmac_bytes(int alg); | 22 | size_t ssh_hmac_bytes(int alg); |
23 | 23 | ||
24 | struct sshbuf; | ||
24 | struct ssh_hmac_ctx; | 25 | struct ssh_hmac_ctx; |
25 | struct ssh_hmac_ctx *ssh_hmac_start(int alg); | 26 | struct ssh_hmac_ctx *ssh_hmac_start(int alg); |
26 | 27 | ||
@@ -29,7 +30,7 @@ int ssh_hmac_init(struct ssh_hmac_ctx *ctx, const void *key, size_t klen) | |||
29 | __attribute__((__bounded__(__buffer__, 2, 3))); | 30 | __attribute__((__bounded__(__buffer__, 2, 3))); |
30 | int ssh_hmac_update(struct ssh_hmac_ctx *ctx, const void *m, size_t mlen) | 31 | int ssh_hmac_update(struct ssh_hmac_ctx *ctx, const void *m, size_t mlen) |
31 | __attribute__((__bounded__(__buffer__, 2, 3))); | 32 | __attribute__((__bounded__(__buffer__, 2, 3))); |
32 | int ssh_hmac_update_buffer(struct ssh_hmac_ctx *ctx, const Buffer *b); | 33 | int ssh_hmac_update_buffer(struct ssh_hmac_ctx *ctx, const struct sshbuf *b); |
33 | int ssh_hmac_final(struct ssh_hmac_ctx *ctx, u_char *d, size_t dlen) | 34 | int ssh_hmac_final(struct ssh_hmac_ctx *ctx, u_char *d, size_t dlen) |
34 | __attribute__((__bounded__(__buffer__, 2, 3))); | 35 | __attribute__((__bounded__(__buffer__, 2, 3))); |
35 | void ssh_hmac_free(struct ssh_hmac_ctx *ctx); | 36 | void ssh_hmac_free(struct ssh_hmac_ctx *ctx); |
diff --git a/hostfile.c b/hostfile.c index 91741cab8..ee2daf45f 100644 --- a/hostfile.c +++ b/hostfile.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: hostfile.c,v 1.56 2014/04/29 18:01:49 markus Exp $ */ | 1 | /* $OpenBSD: hostfile.c,v 1.57 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -47,6 +47,7 @@ | |||
47 | #include <stdio.h> | 47 | #include <stdio.h> |
48 | #include <stdlib.h> | 48 | #include <stdlib.h> |
49 | #include <string.h> | 49 | #include <string.h> |
50 | #include <stdarg.h> | ||
50 | 51 | ||
51 | #include "xmalloc.h" | 52 | #include "xmalloc.h" |
52 | #include "match.h" | 53 | #include "match.h" |
@@ -1,2694 +1,469 @@ | |||
1 | /* $OpenBSD: key.c,v 1.117 2014/04/29 18:01:49 markus Exp $ */ | 1 | /* $OpenBSD: key.c,v 1.119 2014/06/30 12:54:39 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * read_bignum(): | 3 | * placed in the public domain |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||
5 | * | ||
6 | * As far as I am concerned, the code I have written for this software | ||
7 | * can be used freely for any purpose. Any derived versions of this | ||
8 | * software must be clearly marked as such, and if the derived work is | ||
9 | * incompatible with the protocol description in the RFC file, it must be | ||
10 | * called by a name other than "ssh" or "Secure Shell". | ||
11 | * | ||
12 | * | ||
13 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | ||
14 | * Copyright (c) 2008 Alexander von Gernler. All rights reserved. | ||
15 | * | ||
16 | * Redistribution and use in source and binary forms, with or without | ||
17 | * modification, are permitted provided that the following conditions | ||
18 | * are met: | ||
19 | * 1. Redistributions of source code must retain the above copyright | ||
20 | * notice, this list of conditions and the following disclaimer. | ||
21 | * 2. Redistributions in binary form must reproduce the above copyright | ||
22 | * notice, this list of conditions and the following disclaimer in the | ||
23 | * documentation and/or other materials provided with the distribution. | ||
24 | * | ||
25 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
26 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
27 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
28 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
29 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
30 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
34 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
35 | */ | 4 | */ |
36 | 5 | ||
37 | #include "includes.h" | 6 | #include "includes.h" |
38 | 7 | ||
39 | #include <sys/param.h> | 8 | #include <sys/param.h> |
40 | #include <sys/types.h> | 9 | #include <sys/types.h> |
41 | 10 | #include <errno.h> | |
42 | #include "crypto_api.h" | ||
43 | |||
44 | #include <openssl/evp.h> | ||
45 | #include <openbsd-compat/openssl-compat.h> | ||
46 | |||
47 | #include <stdarg.h> | 11 | #include <stdarg.h> |
48 | #include <stdio.h> | 12 | #include <stdio.h> |
49 | #include <string.h> | ||
50 | 13 | ||
51 | #include "xmalloc.h" | 14 | #define SSH_KEY_NO_DEFINE |
52 | #include "key.h" | 15 | #include "key.h" |
53 | #include "rsa.h" | ||
54 | #include "uuencode.h" | ||
55 | #include "buffer.h" | ||
56 | #include "log.h" | ||
57 | #include "misc.h" | ||
58 | #include "ssh2.h" | ||
59 | #include "digest.h" | ||
60 | |||
61 | static int to_blob(const Key *, u_char **, u_int *, int); | ||
62 | static Key *key_from_blob2(const u_char *, u_int, int); | ||
63 | |||
64 | static struct KeyCert * | ||
65 | cert_new(void) | ||
66 | { | ||
67 | struct KeyCert *cert; | ||
68 | |||
69 | cert = xcalloc(1, sizeof(*cert)); | ||
70 | buffer_init(&cert->certblob); | ||
71 | buffer_init(&cert->critical); | ||
72 | buffer_init(&cert->extensions); | ||
73 | cert->key_id = NULL; | ||
74 | cert->principals = NULL; | ||
75 | cert->signature_key = NULL; | ||
76 | return cert; | ||
77 | } | ||
78 | |||
79 | Key * | ||
80 | key_new(int type) | ||
81 | { | ||
82 | Key *k; | ||
83 | #ifdef WITH_OPENSSL | ||
84 | RSA *rsa; | ||
85 | DSA *dsa; | ||
86 | #endif | ||
87 | |||
88 | k = xcalloc(1, sizeof(*k)); | ||
89 | k->type = type; | ||
90 | k->ecdsa = NULL; | ||
91 | k->ecdsa_nid = -1; | ||
92 | k->dsa = NULL; | ||
93 | k->rsa = NULL; | ||
94 | k->cert = NULL; | ||
95 | k->ed25519_sk = NULL; | ||
96 | k->ed25519_pk = NULL; | ||
97 | switch (k->type) { | ||
98 | #ifdef WITH_OPENSSL | ||
99 | case KEY_RSA1: | ||
100 | case KEY_RSA: | ||
101 | case KEY_RSA_CERT_V00: | ||
102 | case KEY_RSA_CERT: | ||
103 | if ((rsa = RSA_new()) == NULL) | ||
104 | fatal("key_new: RSA_new failed"); | ||
105 | if ((rsa->n = BN_new()) == NULL) | ||
106 | fatal("key_new: BN_new failed"); | ||
107 | if ((rsa->e = BN_new()) == NULL) | ||
108 | fatal("key_new: BN_new failed"); | ||
109 | k->rsa = rsa; | ||
110 | break; | ||
111 | case KEY_DSA: | ||
112 | case KEY_DSA_CERT_V00: | ||
113 | case KEY_DSA_CERT: | ||
114 | if ((dsa = DSA_new()) == NULL) | ||
115 | fatal("key_new: DSA_new failed"); | ||
116 | if ((dsa->p = BN_new()) == NULL) | ||
117 | fatal("key_new: BN_new failed"); | ||
118 | if ((dsa->q = BN_new()) == NULL) | ||
119 | fatal("key_new: BN_new failed"); | ||
120 | if ((dsa->g = BN_new()) == NULL) | ||
121 | fatal("key_new: BN_new failed"); | ||
122 | if ((dsa->pub_key = BN_new()) == NULL) | ||
123 | fatal("key_new: BN_new failed"); | ||
124 | k->dsa = dsa; | ||
125 | break; | ||
126 | #ifdef OPENSSL_HAS_ECC | ||
127 | case KEY_ECDSA: | ||
128 | case KEY_ECDSA_CERT: | ||
129 | /* Cannot do anything until we know the group */ | ||
130 | break; | ||
131 | #endif | ||
132 | #endif | ||
133 | case KEY_ED25519: | ||
134 | case KEY_ED25519_CERT: | ||
135 | /* no need to prealloc */ | ||
136 | break; | ||
137 | case KEY_UNSPEC: | ||
138 | break; | ||
139 | default: | ||
140 | fatal("key_new: bad key type %d", k->type); | ||
141 | break; | ||
142 | } | ||
143 | |||
144 | if (key_is_cert(k)) | ||
145 | k->cert = cert_new(); | ||
146 | 16 | ||
147 | return k; | 17 | #include "compat.h" |
148 | } | 18 | #include "sshkey.h" |
19 | #include "ssherr.h" | ||
20 | #include "log.h" | ||
21 | #include "authfile.h" | ||
149 | 22 | ||
150 | void | 23 | void |
151 | key_add_private(Key *k) | 24 | key_add_private(Key *k) |
152 | { | 25 | { |
153 | switch (k->type) { | 26 | int r; |
154 | #ifdef WITH_OPENSSL | 27 | |
155 | case KEY_RSA1: | 28 | if ((r = sshkey_add_private(k)) != 0) |
156 | case KEY_RSA: | 29 | fatal("%s: %s", __func__, ssh_err(r)); |
157 | case KEY_RSA_CERT_V00: | ||
158 | case KEY_RSA_CERT: | ||
159 | if ((k->rsa->d = BN_new()) == NULL) | ||
160 | fatal("key_new_private: BN_new failed"); | ||
161 | if ((k->rsa->iqmp = BN_new()) == NULL) | ||
162 | fatal("key_new_private: BN_new failed"); | ||
163 | if ((k->rsa->q = BN_new()) == NULL) | ||
164 | fatal("key_new_private: BN_new failed"); | ||
165 | if ((k->rsa->p = BN_new()) == NULL) | ||
166 | fatal("key_new_private: BN_new failed"); | ||
167 | if ((k->rsa->dmq1 = BN_new()) == NULL) | ||
168 | fatal("key_new_private: BN_new failed"); | ||
169 | if ((k->rsa->dmp1 = BN_new()) == NULL) | ||
170 | fatal("key_new_private: BN_new failed"); | ||
171 | break; | ||
172 | case KEY_DSA: | ||
173 | case KEY_DSA_CERT_V00: | ||
174 | case KEY_DSA_CERT: | ||
175 | if ((k->dsa->priv_key = BN_new()) == NULL) | ||
176 | fatal("key_new_private: BN_new failed"); | ||
177 | break; | ||
178 | case KEY_ECDSA: | ||
179 | case KEY_ECDSA_CERT: | ||
180 | /* Cannot do anything until we know the group */ | ||
181 | break; | ||
182 | #endif | ||
183 | case KEY_ED25519: | ||
184 | case KEY_ED25519_CERT: | ||
185 | /* no need to prealloc */ | ||
186 | break; | ||
187 | case KEY_UNSPEC: | ||
188 | break; | ||
189 | default: | ||
190 | break; | ||
191 | } | ||
192 | } | 30 | } |
193 | 31 | ||
194 | Key * | 32 | Key * |
195 | key_new_private(int type) | 33 | key_new_private(int type) |
196 | { | 34 | { |
197 | Key *k = key_new(type); | 35 | Key *ret = NULL; |
198 | |||
199 | key_add_private(k); | ||
200 | return k; | ||
201 | } | ||
202 | |||
203 | static void | ||
204 | cert_free(struct KeyCert *cert) | ||
205 | { | ||
206 | u_int i; | ||
207 | |||
208 | buffer_free(&cert->certblob); | ||
209 | buffer_free(&cert->critical); | ||
210 | buffer_free(&cert->extensions); | ||
211 | free(cert->key_id); | ||
212 | for (i = 0; i < cert->nprincipals; i++) | ||
213 | free(cert->principals[i]); | ||
214 | free(cert->principals); | ||
215 | if (cert->signature_key != NULL) | ||
216 | key_free(cert->signature_key); | ||
217 | free(cert); | ||
218 | } | ||
219 | |||
220 | void | ||
221 | key_free(Key *k) | ||
222 | { | ||
223 | if (k == NULL) | ||
224 | fatal("key_free: key is NULL"); | ||
225 | switch (k->type) { | ||
226 | #ifdef WITH_OPENSSL | ||
227 | case KEY_RSA1: | ||
228 | case KEY_RSA: | ||
229 | case KEY_RSA_CERT_V00: | ||
230 | case KEY_RSA_CERT: | ||
231 | if (k->rsa != NULL) | ||
232 | RSA_free(k->rsa); | ||
233 | k->rsa = NULL; | ||
234 | break; | ||
235 | case KEY_DSA: | ||
236 | case KEY_DSA_CERT_V00: | ||
237 | case KEY_DSA_CERT: | ||
238 | if (k->dsa != NULL) | ||
239 | DSA_free(k->dsa); | ||
240 | k->dsa = NULL; | ||
241 | break; | ||
242 | #ifdef OPENSSL_HAS_ECC | ||
243 | case KEY_ECDSA: | ||
244 | case KEY_ECDSA_CERT: | ||
245 | if (k->ecdsa != NULL) | ||
246 | EC_KEY_free(k->ecdsa); | ||
247 | k->ecdsa = NULL; | ||
248 | break; | ||
249 | #endif | ||
250 | case KEY_ED25519: | ||
251 | case KEY_ED25519_CERT: | ||
252 | if (k->ed25519_pk) { | ||
253 | explicit_bzero(k->ed25519_pk, ED25519_PK_SZ); | ||
254 | free(k->ed25519_pk); | ||
255 | k->ed25519_pk = NULL; | ||
256 | } | ||
257 | if (k->ed25519_sk) { | ||
258 | explicit_bzero(k->ed25519_sk, ED25519_SK_SZ); | ||
259 | free(k->ed25519_sk); | ||
260 | k->ed25519_sk = NULL; | ||
261 | } | ||
262 | break; | ||
263 | case KEY_UNSPEC: | ||
264 | break; | ||
265 | default: | ||
266 | fatal("key_free: bad key type %d", k->type); | ||
267 | break; | ||
268 | } | ||
269 | if (key_is_cert(k)) { | ||
270 | if (k->cert != NULL) | ||
271 | cert_free(k->cert); | ||
272 | k->cert = NULL; | ||
273 | } | ||
274 | |||
275 | free(k); | ||
276 | } | ||
277 | |||
278 | static int | ||
279 | cert_compare(struct KeyCert *a, struct KeyCert *b) | ||
280 | { | ||
281 | if (a == NULL && b == NULL) | ||
282 | return 1; | ||
283 | if (a == NULL || b == NULL) | ||
284 | return 0; | ||
285 | if (buffer_len(&a->certblob) != buffer_len(&b->certblob)) | ||
286 | return 0; | ||
287 | if (timingsafe_bcmp(buffer_ptr(&a->certblob), buffer_ptr(&b->certblob), | ||
288 | buffer_len(&a->certblob)) != 0) | ||
289 | return 0; | ||
290 | return 1; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * Compare public portions of key only, allowing comparisons between | ||
295 | * certificates and plain keys too. | ||
296 | */ | ||
297 | int | ||
298 | key_equal_public(const Key *a, const Key *b) | ||
299 | { | ||
300 | #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) | ||
301 | BN_CTX *bnctx; | ||
302 | #endif | ||
303 | |||
304 | if (a == NULL || b == NULL || | ||
305 | key_type_plain(a->type) != key_type_plain(b->type)) | ||
306 | return 0; | ||
307 | |||
308 | switch (a->type) { | ||
309 | #ifdef WITH_OPENSSL | ||
310 | case KEY_RSA1: | ||
311 | case KEY_RSA_CERT_V00: | ||
312 | case KEY_RSA_CERT: | ||
313 | case KEY_RSA: | ||
314 | return a->rsa != NULL && b->rsa != NULL && | ||
315 | BN_cmp(a->rsa->e, b->rsa->e) == 0 && | ||
316 | BN_cmp(a->rsa->n, b->rsa->n) == 0; | ||
317 | case KEY_DSA_CERT_V00: | ||
318 | case KEY_DSA_CERT: | ||
319 | case KEY_DSA: | ||
320 | return a->dsa != NULL && b->dsa != NULL && | ||
321 | BN_cmp(a->dsa->p, b->dsa->p) == 0 && | ||
322 | BN_cmp(a->dsa->q, b->dsa->q) == 0 && | ||
323 | BN_cmp(a->dsa->g, b->dsa->g) == 0 && | ||
324 | BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0; | ||
325 | #ifdef OPENSSL_HAS_ECC | ||
326 | case KEY_ECDSA_CERT: | ||
327 | case KEY_ECDSA: | ||
328 | if (a->ecdsa == NULL || b->ecdsa == NULL || | ||
329 | EC_KEY_get0_public_key(a->ecdsa) == NULL || | ||
330 | EC_KEY_get0_public_key(b->ecdsa) == NULL) | ||
331 | return 0; | ||
332 | if ((bnctx = BN_CTX_new()) == NULL) | ||
333 | fatal("%s: BN_CTX_new failed", __func__); | ||
334 | if (EC_GROUP_cmp(EC_KEY_get0_group(a->ecdsa), | ||
335 | EC_KEY_get0_group(b->ecdsa), bnctx) != 0 || | ||
336 | EC_POINT_cmp(EC_KEY_get0_group(a->ecdsa), | ||
337 | EC_KEY_get0_public_key(a->ecdsa), | ||
338 | EC_KEY_get0_public_key(b->ecdsa), bnctx) != 0) { | ||
339 | BN_CTX_free(bnctx); | ||
340 | return 0; | ||
341 | } | ||
342 | BN_CTX_free(bnctx); | ||
343 | return 1; | ||
344 | #endif /* OPENSSL_HAS_ECC */ | ||
345 | #endif /* WITH_OPENSSL */ | ||
346 | case KEY_ED25519: | ||
347 | case KEY_ED25519_CERT: | ||
348 | return a->ed25519_pk != NULL && b->ed25519_pk != NULL && | ||
349 | memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0; | ||
350 | default: | ||
351 | fatal("key_equal: bad key type %d", a->type); | ||
352 | } | ||
353 | /* NOTREACHED */ | ||
354 | } | ||
355 | 36 | ||
356 | int | 37 | if ((ret = sshkey_new_private(type)) == NULL) |
357 | key_equal(const Key *a, const Key *b) | 38 | fatal("%s: failed", __func__); |
358 | { | 39 | return ret; |
359 | if (a == NULL || b == NULL || a->type != b->type) | ||
360 | return 0; | ||
361 | if (key_is_cert(a)) { | ||
362 | if (!cert_compare(a->cert, b->cert)) | ||
363 | return 0; | ||
364 | } | ||
365 | return key_equal_public(a, b); | ||
366 | } | 40 | } |
367 | 41 | ||
368 | u_char* | 42 | u_char* |
369 | key_fingerprint_raw(const Key *k, enum fp_type dgst_type, | 43 | key_fingerprint_raw(const Key *k, enum fp_type dgst_type, |
370 | u_int *dgst_raw_length) | 44 | u_int *dgst_raw_length) |
371 | { | 45 | { |
372 | u_char *blob = NULL; | 46 | u_char *ret = NULL; |
373 | u_char *retval = NULL; | 47 | size_t dlen; |
374 | u_int len = 0; | 48 | int r; |
375 | int hash_alg = -1; | 49 | |
376 | #ifdef WITH_OPENSSL | 50 | if (dgst_raw_length != NULL) |
377 | int nlen, elen; | 51 | *dgst_raw_length = 0; |
378 | #endif | 52 | if ((r = sshkey_fingerprint_raw(k, dgst_type, &ret, &dlen)) != 0) |
379 | 53 | fatal("%s: %s", __func__, ssh_err(r)); | |
380 | *dgst_raw_length = 0; | 54 | if (dlen > INT_MAX) |
381 | 55 | fatal("%s: giant len %zu", __func__, dlen); | |
382 | /* XXX switch to DIGEST_* directly? */ | 56 | *dgst_raw_length = dlen; |
383 | switch (dgst_type) { | 57 | return ret; |
384 | case SSH_FP_MD5: | ||
385 | hash_alg = SSH_DIGEST_MD5; | ||
386 | break; | ||
387 | case SSH_FP_SHA1: | ||
388 | hash_alg = SSH_DIGEST_SHA1; | ||
389 | break; | ||
390 | case SSH_FP_SHA256: | ||
391 | hash_alg = SSH_DIGEST_SHA256; | ||
392 | break; | ||
393 | default: | ||
394 | fatal("%s: bad digest type %d", __func__, dgst_type); | ||
395 | } | ||
396 | switch (k->type) { | ||
397 | #ifdef WITH_OPENSSL | ||
398 | case KEY_RSA1: | ||
399 | nlen = BN_num_bytes(k->rsa->n); | ||
400 | elen = BN_num_bytes(k->rsa->e); | ||
401 | len = nlen + elen; | ||
402 | blob = xmalloc(len); | ||
403 | BN_bn2bin(k->rsa->n, blob); | ||
404 | BN_bn2bin(k->rsa->e, blob + nlen); | ||
405 | break; | ||
406 | case KEY_DSA: | ||
407 | case KEY_ECDSA: | ||
408 | case KEY_RSA: | ||
409 | #endif | ||
410 | case KEY_ED25519: | ||
411 | key_to_blob(k, &blob, &len); | ||
412 | break; | ||
413 | #ifdef WITH_OPENSSL | ||
414 | case KEY_DSA_CERT_V00: | ||
415 | case KEY_RSA_CERT_V00: | ||
416 | case KEY_DSA_CERT: | ||
417 | case KEY_ECDSA_CERT: | ||
418 | case KEY_RSA_CERT: | ||
419 | #endif | ||
420 | case KEY_ED25519_CERT: | ||
421 | /* We want a fingerprint of the _key_ not of the cert */ | ||
422 | to_blob(k, &blob, &len, 1); | ||
423 | break; | ||
424 | case KEY_UNSPEC: | ||
425 | return retval; | ||
426 | default: | ||
427 | fatal("%s: bad key type %d", __func__, k->type); | ||
428 | break; | ||
429 | } | ||
430 | if (blob != NULL) { | ||
431 | retval = xmalloc(SSH_DIGEST_MAX_LENGTH); | ||
432 | if ((ssh_digest_memory(hash_alg, blob, len, | ||
433 | retval, SSH_DIGEST_MAX_LENGTH)) != 0) | ||
434 | fatal("%s: digest_memory failed", __func__); | ||
435 | explicit_bzero(blob, len); | ||
436 | free(blob); | ||
437 | *dgst_raw_length = ssh_digest_bytes(hash_alg); | ||
438 | } else { | ||
439 | fatal("%s: blob is null", __func__); | ||
440 | } | ||
441 | return retval; | ||
442 | } | ||
443 | |||
444 | static char * | ||
445 | key_fingerprint_hex(u_char *dgst_raw, u_int dgst_raw_len) | ||
446 | { | ||
447 | char *retval; | ||
448 | u_int i; | ||
449 | |||
450 | retval = xcalloc(1, dgst_raw_len * 3 + 1); | ||
451 | for (i = 0; i < dgst_raw_len; i++) { | ||
452 | char hex[4]; | ||
453 | snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]); | ||
454 | strlcat(retval, hex, dgst_raw_len * 3 + 1); | ||
455 | } | ||
456 | |||
457 | /* Remove the trailing ':' character */ | ||
458 | retval[(dgst_raw_len * 3) - 1] = '\0'; | ||
459 | return retval; | ||
460 | } | ||
461 | |||
462 | static char * | ||
463 | key_fingerprint_bubblebabble(u_char *dgst_raw, u_int dgst_raw_len) | ||
464 | { | ||
465 | char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; | ||
466 | char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', | ||
467 | 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' }; | ||
468 | u_int i, j = 0, rounds, seed = 1; | ||
469 | char *retval; | ||
470 | |||
471 | rounds = (dgst_raw_len / 2) + 1; | ||
472 | retval = xcalloc((rounds * 6), sizeof(char)); | ||
473 | retval[j++] = 'x'; | ||
474 | for (i = 0; i < rounds; i++) { | ||
475 | u_int idx0, idx1, idx2, idx3, idx4; | ||
476 | if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) { | ||
477 | idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) + | ||
478 | seed) % 6; | ||
479 | idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15; | ||
480 | idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) + | ||
481 | (seed / 6)) % 6; | ||
482 | retval[j++] = vowels[idx0]; | ||
483 | retval[j++] = consonants[idx1]; | ||
484 | retval[j++] = vowels[idx2]; | ||
485 | if ((i + 1) < rounds) { | ||
486 | idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15; | ||
487 | idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15; | ||
488 | retval[j++] = consonants[idx3]; | ||
489 | retval[j++] = '-'; | ||
490 | retval[j++] = consonants[idx4]; | ||
491 | seed = ((seed * 5) + | ||
492 | ((((u_int)(dgst_raw[2 * i])) * 7) + | ||
493 | ((u_int)(dgst_raw[(2 * i) + 1])))) % 36; | ||
494 | } | ||
495 | } else { | ||
496 | idx0 = seed % 6; | ||
497 | idx1 = 16; | ||
498 | idx2 = seed / 6; | ||
499 | retval[j++] = vowels[idx0]; | ||
500 | retval[j++] = consonants[idx1]; | ||
501 | retval[j++] = vowels[idx2]; | ||
502 | } | ||
503 | } | ||
504 | retval[j++] = 'x'; | ||
505 | retval[j++] = '\0'; | ||
506 | return retval; | ||
507 | } | ||
508 | |||
509 | /* | ||
510 | * Draw an ASCII-Art representing the fingerprint so human brain can | ||
511 | * profit from its built-in pattern recognition ability. | ||
512 | * This technique is called "random art" and can be found in some | ||
513 | * scientific publications like this original paper: | ||
514 | * | ||
515 | * "Hash Visualization: a New Technique to improve Real-World Security", | ||
516 | * Perrig A. and Song D., 1999, International Workshop on Cryptographic | ||
517 | * Techniques and E-Commerce (CrypTEC '99) | ||
518 | * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf | ||
519 | * | ||
520 | * The subject came up in a talk by Dan Kaminsky, too. | ||
521 | * | ||
522 | * If you see the picture is different, the key is different. | ||
523 | * If the picture looks the same, you still know nothing. | ||
524 | * | ||
525 | * The algorithm used here is a worm crawling over a discrete plane, | ||
526 | * leaving a trace (augmenting the field) everywhere it goes. | ||
527 | * Movement is taken from dgst_raw 2bit-wise. Bumping into walls | ||
528 | * makes the respective movement vector be ignored for this turn. | ||
529 | * Graphs are not unambiguous, because circles in graphs can be | ||
530 | * walked in either direction. | ||
531 | */ | ||
532 | |||
533 | /* | ||
534 | * Field sizes for the random art. Have to be odd, so the starting point | ||
535 | * can be in the exact middle of the picture, and FLDBASE should be >=8 . | ||
536 | * Else pictures would be too dense, and drawing the frame would | ||
537 | * fail, too, because the key type would not fit in anymore. | ||
538 | */ | ||
539 | #define FLDBASE 8 | ||
540 | #define FLDSIZE_Y (FLDBASE + 1) | ||
541 | #define FLDSIZE_X (FLDBASE * 2 + 1) | ||
542 | static char * | ||
543 | key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key *k) | ||
544 | { | ||
545 | /* | ||
546 | * Chars to be used after each other every time the worm | ||
547 | * intersects with itself. Matter of taste. | ||
548 | */ | ||
549 | char *augmentation_string = " .o+=*BOX@%&#/^SE"; | ||
550 | char *retval, *p; | ||
551 | u_char field[FLDSIZE_X][FLDSIZE_Y]; | ||
552 | u_int i, b; | ||
553 | int x, y; | ||
554 | size_t len = strlen(augmentation_string) - 1; | ||
555 | |||
556 | retval = xcalloc(1, (FLDSIZE_X + 3) * (FLDSIZE_Y + 2)); | ||
557 | |||
558 | /* initialize field */ | ||
559 | memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char)); | ||
560 | x = FLDSIZE_X / 2; | ||
561 | y = FLDSIZE_Y / 2; | ||
562 | |||
563 | /* process raw key */ | ||
564 | for (i = 0; i < dgst_raw_len; i++) { | ||
565 | int input; | ||
566 | /* each byte conveys four 2-bit move commands */ | ||
567 | input = dgst_raw[i]; | ||
568 | for (b = 0; b < 4; b++) { | ||
569 | /* evaluate 2 bit, rest is shifted later */ | ||
570 | x += (input & 0x1) ? 1 : -1; | ||
571 | y += (input & 0x2) ? 1 : -1; | ||
572 | |||
573 | /* assure we are still in bounds */ | ||
574 | x = MAX(x, 0); | ||
575 | y = MAX(y, 0); | ||
576 | x = MIN(x, FLDSIZE_X - 1); | ||
577 | y = MIN(y, FLDSIZE_Y - 1); | ||
578 | |||
579 | /* augment the field */ | ||
580 | if (field[x][y] < len - 2) | ||
581 | field[x][y]++; | ||
582 | input = input >> 2; | ||
583 | } | ||
584 | } | ||
585 | |||
586 | /* mark starting point and end point*/ | ||
587 | field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1; | ||
588 | field[x][y] = len; | ||
589 | |||
590 | /* fill in retval */ | ||
591 | snprintf(retval, FLDSIZE_X, "+--[%4s %4u]", key_type(k), key_size(k)); | ||
592 | p = strchr(retval, '\0'); | ||
593 | |||
594 | /* output upper border */ | ||
595 | for (i = p - retval - 1; i < FLDSIZE_X; i++) | ||
596 | *p++ = '-'; | ||
597 | *p++ = '+'; | ||
598 | *p++ = '\n'; | ||
599 | |||
600 | /* output content */ | ||
601 | for (y = 0; y < FLDSIZE_Y; y++) { | ||
602 | *p++ = '|'; | ||
603 | for (x = 0; x < FLDSIZE_X; x++) | ||
604 | *p++ = augmentation_string[MIN(field[x][y], len)]; | ||
605 | *p++ = '|'; | ||
606 | *p++ = '\n'; | ||
607 | } | ||
608 | |||
609 | /* output lower border */ | ||
610 | *p++ = '+'; | ||
611 | for (i = 0; i < FLDSIZE_X; i++) | ||
612 | *p++ = '-'; | ||
613 | *p++ = '+'; | ||
614 | |||
615 | return retval; | ||
616 | } | ||
617 | |||
618 | char * | ||
619 | key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) | ||
620 | { | ||
621 | char *retval = NULL; | ||
622 | u_char *dgst_raw; | ||
623 | u_int dgst_raw_len; | ||
624 | |||
625 | dgst_raw = key_fingerprint_raw(k, dgst_type, &dgst_raw_len); | ||
626 | if (!dgst_raw) | ||
627 | fatal("key_fingerprint: null from key_fingerprint_raw()"); | ||
628 | switch (dgst_rep) { | ||
629 | case SSH_FP_HEX: | ||
630 | retval = key_fingerprint_hex(dgst_raw, dgst_raw_len); | ||
631 | break; | ||
632 | case SSH_FP_BUBBLEBABBLE: | ||
633 | retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len); | ||
634 | break; | ||
635 | case SSH_FP_RANDOMART: | ||
636 | retval = key_fingerprint_randomart(dgst_raw, dgst_raw_len, k); | ||
637 | break; | ||
638 | default: | ||
639 | fatal("key_fingerprint: bad digest representation %d", | ||
640 | dgst_rep); | ||
641 | break; | ||
642 | } | ||
643 | explicit_bzero(dgst_raw, dgst_raw_len); | ||
644 | free(dgst_raw); | ||
645 | return retval; | ||
646 | } | ||
647 | |||
648 | #ifdef WITH_SSH1 | ||
649 | /* | ||
650 | * Reads a multiple-precision integer in decimal from the buffer, and advances | ||
651 | * the pointer. The integer must already be initialized. This function is | ||
652 | * permitted to modify the buffer. This leaves *cpp to point just beyond the | ||
653 | * last processed (and maybe modified) character. Note that this may modify | ||
654 | * the buffer containing the number. | ||
655 | */ | ||
656 | static int | ||
657 | read_bignum(char **cpp, BIGNUM * value) | ||
658 | { | ||
659 | char *cp = *cpp; | ||
660 | int old; | ||
661 | |||
662 | /* Skip any leading whitespace. */ | ||
663 | for (; *cp == ' ' || *cp == '\t'; cp++) | ||
664 | ; | ||
665 | |||
666 | /* Check that it begins with a decimal digit. */ | ||
667 | if (*cp < '0' || *cp > '9') | ||
668 | return 0; | ||
669 | |||
670 | /* Save starting position. */ | ||
671 | *cpp = cp; | ||
672 | |||
673 | /* Move forward until all decimal digits skipped. */ | ||
674 | for (; *cp >= '0' && *cp <= '9'; cp++) | ||
675 | ; | ||
676 | |||
677 | /* Save the old terminating character, and replace it by \0. */ | ||
678 | old = *cp; | ||
679 | *cp = 0; | ||
680 | |||
681 | /* Parse the number. */ | ||
682 | if (BN_dec2bn(&value, *cpp) == 0) | ||
683 | return 0; | ||
684 | |||
685 | /* Restore old terminating character. */ | ||
686 | *cp = old; | ||
687 | |||
688 | /* Move beyond the number and return success. */ | ||
689 | *cpp = cp; | ||
690 | return 1; | ||
691 | } | ||
692 | |||
693 | static int | ||
694 | write_bignum(FILE *f, BIGNUM *num) | ||
695 | { | ||
696 | char *buf = BN_bn2dec(num); | ||
697 | if (buf == NULL) { | ||
698 | error("write_bignum: BN_bn2dec() failed"); | ||
699 | return 0; | ||
700 | } | ||
701 | fprintf(f, " %s", buf); | ||
702 | OPENSSL_free(buf); | ||
703 | return 1; | ||
704 | } | 58 | } |
705 | #endif | ||
706 | 59 | ||
707 | /* returns 1 ok, -1 error */ | ||
708 | int | 60 | int |
709 | key_read(Key *ret, char **cpp) | 61 | key_read(Key *ret, char **cpp) |
710 | { | 62 | { |
711 | Key *k; | 63 | return sshkey_read(ret, cpp) == 0 ? 1 : -1; |
712 | int success = -1; | ||
713 | char *cp, *space; | ||
714 | int len, n, type; | ||
715 | u_char *blob; | ||
716 | #ifdef WITH_SSH1 | ||
717 | u_int bits; | ||
718 | #endif | ||
719 | #ifdef OPENSSL_HAS_ECC | ||
720 | int curve_nid = -1; | ||
721 | #endif | ||
722 | |||
723 | cp = *cpp; | ||
724 | |||
725 | switch (ret->type) { | ||
726 | case KEY_RSA1: | ||
727 | #ifdef WITH_SSH1 | ||
728 | /* Get number of bits. */ | ||
729 | if (*cp < '0' || *cp > '9') | ||
730 | return -1; /* Bad bit count... */ | ||
731 | for (bits = 0; *cp >= '0' && *cp <= '9'; cp++) | ||
732 | bits = 10 * bits + *cp - '0'; | ||
733 | if (bits == 0) | ||
734 | return -1; | ||
735 | *cpp = cp; | ||
736 | /* Get public exponent, public modulus. */ | ||
737 | if (!read_bignum(cpp, ret->rsa->e)) | ||
738 | return -1; | ||
739 | if (!read_bignum(cpp, ret->rsa->n)) | ||
740 | return -1; | ||
741 | /* validate the claimed number of bits */ | ||
742 | if ((u_int)BN_num_bits(ret->rsa->n) != bits) { | ||
743 | verbose("key_read: claimed key size %d does not match " | ||
744 | "actual %d", bits, BN_num_bits(ret->rsa->n)); | ||
745 | return -1; | ||
746 | } | ||
747 | success = 1; | ||
748 | #endif | ||
749 | break; | ||
750 | case KEY_UNSPEC: | ||
751 | case KEY_RSA: | ||
752 | case KEY_DSA: | ||
753 | case KEY_ECDSA: | ||
754 | case KEY_ED25519: | ||
755 | case KEY_DSA_CERT_V00: | ||
756 | case KEY_RSA_CERT_V00: | ||
757 | case KEY_DSA_CERT: | ||
758 | case KEY_ECDSA_CERT: | ||
759 | case KEY_RSA_CERT: | ||
760 | case KEY_ED25519_CERT: | ||
761 | space = strchr(cp, ' '); | ||
762 | if (space == NULL) { | ||
763 | debug3("key_read: missing whitespace"); | ||
764 | return -1; | ||
765 | } | ||
766 | *space = '\0'; | ||
767 | type = key_type_from_name(cp); | ||
768 | #ifdef OPENSSL_HAS_ECC | ||
769 | if (key_type_plain(type) == KEY_ECDSA && | ||
770 | (curve_nid = key_ecdsa_nid_from_name(cp)) == -1) { | ||
771 | debug("key_read: invalid curve"); | ||
772 | return -1; | ||
773 | } | ||
774 | #endif | ||
775 | *space = ' '; | ||
776 | if (type == KEY_UNSPEC) { | ||
777 | debug3("key_read: missing keytype"); | ||
778 | return -1; | ||
779 | } | ||
780 | cp = space+1; | ||
781 | if (*cp == '\0') { | ||
782 | debug3("key_read: short string"); | ||
783 | return -1; | ||
784 | } | ||
785 | if (ret->type == KEY_UNSPEC) { | ||
786 | ret->type = type; | ||
787 | } else if (ret->type != type) { | ||
788 | /* is a key, but different type */ | ||
789 | debug3("key_read: type mismatch"); | ||
790 | return -1; | ||
791 | } | ||
792 | len = 2*strlen(cp); | ||
793 | blob = xmalloc(len); | ||
794 | n = uudecode(cp, blob, len); | ||
795 | if (n < 0) { | ||
796 | error("key_read: uudecode %s failed", cp); | ||
797 | free(blob); | ||
798 | return -1; | ||
799 | } | ||
800 | k = key_from_blob(blob, (u_int)n); | ||
801 | free(blob); | ||
802 | if (k == NULL) { | ||
803 | error("key_read: key_from_blob %s failed", cp); | ||
804 | return -1; | ||
805 | } | ||
806 | if (k->type != type) { | ||
807 | error("key_read: type mismatch: encoding error"); | ||
808 | key_free(k); | ||
809 | return -1; | ||
810 | } | ||
811 | #ifdef OPENSSL_HAS_ECC | ||
812 | if (key_type_plain(type) == KEY_ECDSA && | ||
813 | curve_nid != k->ecdsa_nid) { | ||
814 | error("key_read: type mismatch: EC curve mismatch"); | ||
815 | key_free(k); | ||
816 | return -1; | ||
817 | } | ||
818 | #endif | ||
819 | /*XXXX*/ | ||
820 | if (key_is_cert(ret)) { | ||
821 | if (!key_is_cert(k)) { | ||
822 | error("key_read: loaded key is not a cert"); | ||
823 | key_free(k); | ||
824 | return -1; | ||
825 | } | ||
826 | if (ret->cert != NULL) | ||
827 | cert_free(ret->cert); | ||
828 | ret->cert = k->cert; | ||
829 | k->cert = NULL; | ||
830 | } | ||
831 | #ifdef WITH_OPENSSL | ||
832 | if (key_type_plain(ret->type) == KEY_RSA) { | ||
833 | if (ret->rsa != NULL) | ||
834 | RSA_free(ret->rsa); | ||
835 | ret->rsa = k->rsa; | ||
836 | k->rsa = NULL; | ||
837 | #ifdef DEBUG_PK | ||
838 | RSA_print_fp(stderr, ret->rsa, 8); | ||
839 | #endif | ||
840 | } | ||
841 | if (key_type_plain(ret->type) == KEY_DSA) { | ||
842 | if (ret->dsa != NULL) | ||
843 | DSA_free(ret->dsa); | ||
844 | ret->dsa = k->dsa; | ||
845 | k->dsa = NULL; | ||
846 | #ifdef DEBUG_PK | ||
847 | DSA_print_fp(stderr, ret->dsa, 8); | ||
848 | #endif | ||
849 | } | ||
850 | #ifdef OPENSSL_HAS_ECC | ||
851 | if (key_type_plain(ret->type) == KEY_ECDSA) { | ||
852 | if (ret->ecdsa != NULL) | ||
853 | EC_KEY_free(ret->ecdsa); | ||
854 | ret->ecdsa = k->ecdsa; | ||
855 | ret->ecdsa_nid = k->ecdsa_nid; | ||
856 | k->ecdsa = NULL; | ||
857 | k->ecdsa_nid = -1; | ||
858 | #ifdef DEBUG_PK | ||
859 | key_dump_ec_key(ret->ecdsa); | ||
860 | #endif | ||
861 | } | ||
862 | #endif | ||
863 | #endif | ||
864 | if (key_type_plain(ret->type) == KEY_ED25519) { | ||
865 | free(ret->ed25519_pk); | ||
866 | ret->ed25519_pk = k->ed25519_pk; | ||
867 | k->ed25519_pk = NULL; | ||
868 | #ifdef DEBUG_PK | ||
869 | /* XXX */ | ||
870 | #endif | ||
871 | } | ||
872 | success = 1; | ||
873 | /*XXXX*/ | ||
874 | key_free(k); | ||
875 | if (success != 1) | ||
876 | break; | ||
877 | /* advance cp: skip whitespace and data */ | ||
878 | while (*cp == ' ' || *cp == '\t') | ||
879 | cp++; | ||
880 | while (*cp != '\0' && *cp != ' ' && *cp != '\t') | ||
881 | cp++; | ||
882 | *cpp = cp; | ||
883 | break; | ||
884 | default: | ||
885 | fatal("key_read: bad key type: %d", ret->type); | ||
886 | break; | ||
887 | } | ||
888 | return success; | ||
889 | } | 64 | } |
890 | 65 | ||
891 | int | 66 | int |
892 | key_write(const Key *key, FILE *f) | 67 | key_write(const Key *key, FILE *f) |
893 | { | 68 | { |
894 | int n, success = 0; | 69 | return sshkey_write(key, f) == 0 ? 1 : 0; |
895 | #ifdef WITH_SSH1 | ||
896 | u_int bits = 0; | ||
897 | #endif | ||
898 | u_int len; | ||
899 | u_char *blob; | ||
900 | char *uu; | ||
901 | |||
902 | if (key_is_cert(key)) { | ||
903 | if (key->cert == NULL) { | ||
904 | error("%s: no cert data", __func__); | ||
905 | return 0; | ||
906 | } | ||
907 | if (buffer_len(&key->cert->certblob) == 0) { | ||
908 | error("%s: no signed certificate blob", __func__); | ||
909 | return 0; | ||
910 | } | ||
911 | } | ||
912 | |||
913 | switch (key->type) { | ||
914 | #ifdef WITH_SSH1 | ||
915 | case KEY_RSA1: | ||
916 | if (key->rsa == NULL) | ||
917 | return 0; | ||
918 | /* size of modulus 'n' */ | ||
919 | bits = BN_num_bits(key->rsa->n); | ||
920 | fprintf(f, "%u", bits); | ||
921 | if (write_bignum(f, key->rsa->e) && | ||
922 | write_bignum(f, key->rsa->n)) | ||
923 | return 1; | ||
924 | error("key_write: failed for RSA key"); | ||
925 | return 0; | ||
926 | #endif | ||
927 | #ifdef WITH_OPENSSL | ||
928 | case KEY_DSA: | ||
929 | case KEY_DSA_CERT_V00: | ||
930 | case KEY_DSA_CERT: | ||
931 | if (key->dsa == NULL) | ||
932 | return 0; | ||
933 | break; | ||
934 | #ifdef OPENSSL_HAS_ECC | ||
935 | case KEY_ECDSA: | ||
936 | case KEY_ECDSA_CERT: | ||
937 | if (key->ecdsa == NULL) | ||
938 | return 0; | ||
939 | break; | ||
940 | #endif | ||
941 | case KEY_RSA: | ||
942 | case KEY_RSA_CERT_V00: | ||
943 | case KEY_RSA_CERT: | ||
944 | if (key->rsa == NULL) | ||
945 | return 0; | ||
946 | break; | ||
947 | #endif | ||
948 | case KEY_ED25519: | ||
949 | case KEY_ED25519_CERT: | ||
950 | if (key->ed25519_pk == NULL) | ||
951 | return 0; | ||
952 | break; | ||
953 | default: | ||
954 | return 0; | ||
955 | } | ||
956 | |||
957 | key_to_blob(key, &blob, &len); | ||
958 | uu = xmalloc(2*len); | ||
959 | n = uuencode(blob, len, uu, 2*len); | ||
960 | if (n > 0) { | ||
961 | fprintf(f, "%s %s", key_ssh_name(key), uu); | ||
962 | success = 1; | ||
963 | } | ||
964 | free(blob); | ||
965 | free(uu); | ||
966 | |||
967 | return success; | ||
968 | } | ||
969 | |||
970 | const char * | ||
971 | key_cert_type(const Key *k) | ||
972 | { | ||
973 | switch (k->cert->type) { | ||
974 | case SSH2_CERT_TYPE_USER: | ||
975 | return "user"; | ||
976 | case SSH2_CERT_TYPE_HOST: | ||
977 | return "host"; | ||
978 | default: | ||
979 | return "unknown"; | ||
980 | } | ||
981 | } | ||
982 | |||
983 | struct keytype { | ||
984 | char *name; | ||
985 | char *shortname; | ||
986 | int type; | ||
987 | int nid; | ||
988 | int cert; | ||
989 | }; | ||
990 | static const struct keytype keytypes[] = { | ||
991 | #ifdef WITH_OPENSSL | ||
992 | #ifdef WITH_SSH1 | ||
993 | { NULL, "RSA1", KEY_RSA1, 0, 0 }, | ||
994 | #endif | ||
995 | { "ssh-rsa", "RSA", KEY_RSA, 0, 0 }, | ||
996 | { "ssh-dss", "DSA", KEY_DSA, 0, 0 }, | ||
997 | #ifdef OPENSSL_HAS_ECC | ||
998 | { "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0 }, | ||
999 | { "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0 }, | ||
1000 | # ifdef OPENSSL_HAS_NISTP521 | ||
1001 | { "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0 }, | ||
1002 | # endif | ||
1003 | #endif /* OPENSSL_HAS_ECC */ | ||
1004 | { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", KEY_RSA_CERT, 0, 1 }, | ||
1005 | { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", KEY_DSA_CERT, 0, 1 }, | ||
1006 | #ifdef OPENSSL_HAS_ECC | ||
1007 | { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT", | ||
1008 | KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1 }, | ||
1009 | { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT", | ||
1010 | KEY_ECDSA_CERT, NID_secp384r1, 1 }, | ||
1011 | # ifdef OPENSSL_HAS_NISTP521 | ||
1012 | { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT", | ||
1013 | KEY_ECDSA_CERT, NID_secp521r1, 1 }, | ||
1014 | # endif | ||
1015 | #endif /* OPENSSL_HAS_ECC */ | ||
1016 | { "ssh-rsa-cert-v00@openssh.com", "RSA-CERT-V00", | ||
1017 | KEY_RSA_CERT_V00, 0, 1 }, | ||
1018 | { "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00", | ||
1019 | KEY_DSA_CERT_V00, 0, 1 }, | ||
1020 | #endif | ||
1021 | { "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0 }, | ||
1022 | { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", | ||
1023 | KEY_ED25519_CERT, 0, 1 }, | ||
1024 | { NULL, NULL, -1, -1, 0 } | ||
1025 | }; | ||
1026 | |||
1027 | const char * | ||
1028 | key_type(const Key *k) | ||
1029 | { | ||
1030 | const struct keytype *kt; | ||
1031 | |||
1032 | for (kt = keytypes; kt->type != -1; kt++) { | ||
1033 | if (kt->type == k->type) | ||
1034 | return kt->shortname; | ||
1035 | } | ||
1036 | return "unknown"; | ||
1037 | } | ||
1038 | |||
1039 | static const char * | ||
1040 | key_ssh_name_from_type_nid(int type, int nid) | ||
1041 | { | ||
1042 | const struct keytype *kt; | ||
1043 | |||
1044 | for (kt = keytypes; kt->type != -1; kt++) { | ||
1045 | if (kt->type == type && (kt->nid == 0 || kt->nid == nid)) | ||
1046 | return kt->name; | ||
1047 | } | ||
1048 | return "ssh-unknown"; | ||
1049 | } | ||
1050 | |||
1051 | const char * | ||
1052 | key_ssh_name(const Key *k) | ||
1053 | { | ||
1054 | return key_ssh_name_from_type_nid(k->type, k->ecdsa_nid); | ||
1055 | } | ||
1056 | |||
1057 | const char * | ||
1058 | key_ssh_name_plain(const Key *k) | ||
1059 | { | ||
1060 | return key_ssh_name_from_type_nid(key_type_plain(k->type), | ||
1061 | k->ecdsa_nid); | ||
1062 | } | ||
1063 | |||
1064 | int | ||
1065 | key_type_from_name(char *name) | ||
1066 | { | ||
1067 | const struct keytype *kt; | ||
1068 | |||
1069 | for (kt = keytypes; kt->type != -1; kt++) { | ||
1070 | /* Only allow shortname matches for plain key types */ | ||
1071 | if ((kt->name != NULL && strcmp(name, kt->name) == 0) || | ||
1072 | (!kt->cert && strcasecmp(kt->shortname, name) == 0)) | ||
1073 | return kt->type; | ||
1074 | } | ||
1075 | debug2("key_type_from_name: unknown key type '%s'", name); | ||
1076 | return KEY_UNSPEC; | ||
1077 | } | ||
1078 | |||
1079 | int | ||
1080 | key_ecdsa_nid_from_name(const char *name) | ||
1081 | { | ||
1082 | const struct keytype *kt; | ||
1083 | |||
1084 | for (kt = keytypes; kt->type != -1; kt++) { | ||
1085 | if (kt->type != KEY_ECDSA && kt->type != KEY_ECDSA_CERT) | ||
1086 | continue; | ||
1087 | if (kt->name != NULL && strcmp(name, kt->name) == 0) | ||
1088 | return kt->nid; | ||
1089 | } | ||
1090 | debug2("%s: unknown/non-ECDSA key type '%s'", __func__, name); | ||
1091 | return -1; | ||
1092 | } | ||
1093 | |||
1094 | char * | ||
1095 | key_alg_list(int certs_only, int plain_only) | ||
1096 | { | ||
1097 | char *ret = NULL; | ||
1098 | size_t nlen, rlen = 0; | ||
1099 | const struct keytype *kt; | ||
1100 | |||
1101 | for (kt = keytypes; kt->type != -1; kt++) { | ||
1102 | if (kt->name == NULL) | ||
1103 | continue; | ||
1104 | if ((certs_only && !kt->cert) || (plain_only && kt->cert)) | ||
1105 | continue; | ||
1106 | if (ret != NULL) | ||
1107 | ret[rlen++] = '\n'; | ||
1108 | nlen = strlen(kt->name); | ||
1109 | ret = xrealloc(ret, 1, rlen + nlen + 2); | ||
1110 | memcpy(ret + rlen, kt->name, nlen + 1); | ||
1111 | rlen += nlen; | ||
1112 | } | ||
1113 | return ret; | ||
1114 | } | ||
1115 | |||
1116 | int | ||
1117 | key_type_is_cert(int type) | ||
1118 | { | ||
1119 | const struct keytype *kt; | ||
1120 | |||
1121 | for (kt = keytypes; kt->type != -1; kt++) { | ||
1122 | if (kt->type == type) | ||
1123 | return kt->cert; | ||
1124 | } | ||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | static int | ||
1129 | key_type_is_valid_ca(int type) | ||
1130 | { | ||
1131 | switch (type) { | ||
1132 | case KEY_RSA: | ||
1133 | case KEY_DSA: | ||
1134 | case KEY_ECDSA: | ||
1135 | case KEY_ED25519: | ||
1136 | return 1; | ||
1137 | default: | ||
1138 | return 0; | ||
1139 | } | ||
1140 | } | ||
1141 | |||
1142 | u_int | ||
1143 | key_size(const Key *k) | ||
1144 | { | ||
1145 | switch (k->type) { | ||
1146 | #ifdef WITH_OPENSSL | ||
1147 | case KEY_RSA1: | ||
1148 | case KEY_RSA: | ||
1149 | case KEY_RSA_CERT_V00: | ||
1150 | case KEY_RSA_CERT: | ||
1151 | return BN_num_bits(k->rsa->n); | ||
1152 | case KEY_DSA: | ||
1153 | case KEY_DSA_CERT_V00: | ||
1154 | case KEY_DSA_CERT: | ||
1155 | return BN_num_bits(k->dsa->p); | ||
1156 | #ifdef OPENSSL_HAS_ECC | ||
1157 | case KEY_ECDSA: | ||
1158 | case KEY_ECDSA_CERT: | ||
1159 | return key_curve_nid_to_bits(k->ecdsa_nid); | ||
1160 | #endif | ||
1161 | #endif | ||
1162 | case KEY_ED25519: | ||
1163 | return 256; /* XXX */ | ||
1164 | } | ||
1165 | return 0; | ||
1166 | } | ||
1167 | |||
1168 | #ifdef WITH_OPENSSL | ||
1169 | static RSA * | ||
1170 | rsa_generate_private_key(u_int bits) | ||
1171 | { | ||
1172 | RSA *private = RSA_new(); | ||
1173 | BIGNUM *f4 = BN_new(); | ||
1174 | |||
1175 | if (private == NULL) | ||
1176 | fatal("%s: RSA_new failed", __func__); | ||
1177 | if (f4 == NULL) | ||
1178 | fatal("%s: BN_new failed", __func__); | ||
1179 | if (!BN_set_word(f4, RSA_F4)) | ||
1180 | fatal("%s: BN_new failed", __func__); | ||
1181 | if (!RSA_generate_key_ex(private, bits, f4, NULL)) | ||
1182 | fatal("%s: key generation failed.", __func__); | ||
1183 | BN_free(f4); | ||
1184 | return private; | ||
1185 | } | ||
1186 | |||
1187 | static DSA* | ||
1188 | dsa_generate_private_key(u_int bits) | ||
1189 | { | ||
1190 | DSA *private = DSA_new(); | ||
1191 | |||
1192 | if (private == NULL) | ||
1193 | fatal("%s: DSA_new failed", __func__); | ||
1194 | if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL, | ||
1195 | NULL, NULL)) | ||
1196 | fatal("%s: DSA_generate_parameters failed", __func__); | ||
1197 | if (!DSA_generate_key(private)) | ||
1198 | fatal("%s: DSA_generate_key failed.", __func__); | ||
1199 | return private; | ||
1200 | } | ||
1201 | |||
1202 | int | ||
1203 | key_ecdsa_bits_to_nid(int bits) | ||
1204 | { | ||
1205 | switch (bits) { | ||
1206 | #ifdef OPENSSL_HAS_ECC | ||
1207 | case 256: | ||
1208 | return NID_X9_62_prime256v1; | ||
1209 | case 384: | ||
1210 | return NID_secp384r1; | ||
1211 | # ifdef OPENSSL_HAS_NISTP521 | ||
1212 | case 521: | ||
1213 | return NID_secp521r1; | ||
1214 | # endif | ||
1215 | #endif | ||
1216 | default: | ||
1217 | return -1; | ||
1218 | } | ||
1219 | } | ||
1220 | |||
1221 | #ifdef OPENSSL_HAS_ECC | ||
1222 | int | ||
1223 | key_ecdsa_key_to_nid(EC_KEY *k) | ||
1224 | { | ||
1225 | EC_GROUP *eg; | ||
1226 | int nids[] = { | ||
1227 | NID_X9_62_prime256v1, | ||
1228 | NID_secp384r1, | ||
1229 | # ifdef OPENSSL_HAS_NISTP521 | ||
1230 | NID_secp521r1, | ||
1231 | # endif | ||
1232 | -1 | ||
1233 | }; | ||
1234 | int nid; | ||
1235 | u_int i; | ||
1236 | BN_CTX *bnctx; | ||
1237 | const EC_GROUP *g = EC_KEY_get0_group(k); | ||
1238 | |||
1239 | /* | ||
1240 | * The group may be stored in a ASN.1 encoded private key in one of two | ||
1241 | * ways: as a "named group", which is reconstituted by ASN.1 object ID | ||
1242 | * or explicit group parameters encoded into the key blob. Only the | ||
1243 | * "named group" case sets the group NID for us, but we can figure | ||
1244 | * it out for the other case by comparing against all the groups that | ||
1245 | * are supported. | ||
1246 | */ | ||
1247 | if ((nid = EC_GROUP_get_curve_name(g)) > 0) | ||
1248 | return nid; | ||
1249 | if ((bnctx = BN_CTX_new()) == NULL) | ||
1250 | fatal("%s: BN_CTX_new() failed", __func__); | ||
1251 | for (i = 0; nids[i] != -1; i++) { | ||
1252 | if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL) | ||
1253 | fatal("%s: EC_GROUP_new_by_curve_name failed", | ||
1254 | __func__); | ||
1255 | if (EC_GROUP_cmp(g, eg, bnctx) == 0) | ||
1256 | break; | ||
1257 | EC_GROUP_free(eg); | ||
1258 | } | ||
1259 | BN_CTX_free(bnctx); | ||
1260 | debug3("%s: nid = %d", __func__, nids[i]); | ||
1261 | if (nids[i] != -1) { | ||
1262 | /* Use the group with the NID attached */ | ||
1263 | EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE); | ||
1264 | if (EC_KEY_set_group(k, eg) != 1) | ||
1265 | fatal("%s: EC_KEY_set_group", __func__); | ||
1266 | } | ||
1267 | return nids[i]; | ||
1268 | } | 70 | } |
1269 | 71 | ||
1270 | static EC_KEY* | ||
1271 | ecdsa_generate_private_key(u_int bits, int *nid) | ||
1272 | { | ||
1273 | EC_KEY *private; | ||
1274 | |||
1275 | if ((*nid = key_ecdsa_bits_to_nid(bits)) == -1) | ||
1276 | fatal("%s: invalid key length", __func__); | ||
1277 | if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL) | ||
1278 | fatal("%s: EC_KEY_new_by_curve_name failed", __func__); | ||
1279 | if (EC_KEY_generate_key(private) != 1) | ||
1280 | fatal("%s: EC_KEY_generate_key failed", __func__); | ||
1281 | EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE); | ||
1282 | return private; | ||
1283 | } | ||
1284 | #endif /* OPENSSL_HAS_ECC */ | ||
1285 | #endif /* WITH_OPENSSL */ | ||
1286 | |||
1287 | Key * | 72 | Key * |
1288 | key_generate(int type, u_int bits) | 73 | key_generate(int type, u_int bits) |
1289 | { | 74 | { |
1290 | Key *k = key_new(KEY_UNSPEC); | 75 | int r; |
1291 | switch (type) { | 76 | Key *ret = NULL; |
1292 | #ifdef WITH_OPENSSL | 77 | |
1293 | case KEY_DSA: | 78 | if ((r = sshkey_generate(type, bits, &ret)) != 0) |
1294 | k->dsa = dsa_generate_private_key(bits); | 79 | fatal("%s: %s", __func__, ssh_err(r)); |
1295 | break; | 80 | return ret; |
1296 | #ifdef OPENSSL_HAS_ECC | ||
1297 | case KEY_ECDSA: | ||
1298 | k->ecdsa = ecdsa_generate_private_key(bits, &k->ecdsa_nid); | ||
1299 | break; | ||
1300 | #endif | ||
1301 | case KEY_RSA: | ||
1302 | case KEY_RSA1: | ||
1303 | k->rsa = rsa_generate_private_key(bits); | ||
1304 | break; | ||
1305 | #endif | ||
1306 | case KEY_RSA_CERT_V00: | ||
1307 | case KEY_DSA_CERT_V00: | ||
1308 | case KEY_RSA_CERT: | ||
1309 | case KEY_DSA_CERT: | ||
1310 | fatal("key_generate: cert keys cannot be generated directly"); | ||
1311 | #endif | ||
1312 | case KEY_ED25519: | ||
1313 | k->ed25519_pk = xmalloc(ED25519_PK_SZ); | ||
1314 | k->ed25519_sk = xmalloc(ED25519_SK_SZ); | ||
1315 | crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk); | ||
1316 | break; | ||
1317 | default: | ||
1318 | fatal("key_generate: unknown type %d", type); | ||
1319 | } | ||
1320 | k->type = type; | ||
1321 | return k; | ||
1322 | } | 81 | } |
1323 | 82 | ||
1324 | void | 83 | void |
1325 | key_cert_copy(const Key *from_key, struct Key *to_key) | 84 | key_cert_copy(const Key *from_key, Key *to_key) |
1326 | { | 85 | { |
1327 | u_int i; | 86 | int r; |
1328 | const struct KeyCert *from; | ||
1329 | struct KeyCert *to; | ||
1330 | |||
1331 | if (to_key->cert != NULL) { | ||
1332 | cert_free(to_key->cert); | ||
1333 | to_key->cert = NULL; | ||
1334 | } | ||
1335 | 87 | ||
1336 | if ((from = from_key->cert) == NULL) | 88 | if ((r = sshkey_cert_copy(from_key, to_key)) != 0) |
1337 | return; | 89 | fatal("%s: %s", __func__, ssh_err(r)); |
1338 | |||
1339 | to = to_key->cert = cert_new(); | ||
1340 | |||
1341 | buffer_append(&to->certblob, buffer_ptr(&from->certblob), | ||
1342 | buffer_len(&from->certblob)); | ||
1343 | |||
1344 | buffer_append(&to->critical, | ||
1345 | buffer_ptr(&from->critical), buffer_len(&from->critical)); | ||
1346 | buffer_append(&to->extensions, | ||
1347 | buffer_ptr(&from->extensions), buffer_len(&from->extensions)); | ||
1348 | |||
1349 | to->serial = from->serial; | ||
1350 | to->type = from->type; | ||
1351 | to->key_id = from->key_id == NULL ? NULL : xstrdup(from->key_id); | ||
1352 | to->valid_after = from->valid_after; | ||
1353 | to->valid_before = from->valid_before; | ||
1354 | to->signature_key = from->signature_key == NULL ? | ||
1355 | NULL : key_from_private(from->signature_key); | ||
1356 | |||
1357 | to->nprincipals = from->nprincipals; | ||
1358 | if (to->nprincipals > CERT_MAX_PRINCIPALS) | ||
1359 | fatal("%s: nprincipals (%u) > CERT_MAX_PRINCIPALS (%u)", | ||
1360 | __func__, to->nprincipals, CERT_MAX_PRINCIPALS); | ||
1361 | if (to->nprincipals > 0) { | ||
1362 | to->principals = xcalloc(from->nprincipals, | ||
1363 | sizeof(*to->principals)); | ||
1364 | for (i = 0; i < to->nprincipals; i++) | ||
1365 | to->principals[i] = xstrdup(from->principals[i]); | ||
1366 | } | ||
1367 | } | 90 | } |
1368 | 91 | ||
1369 | Key * | 92 | Key * |
1370 | key_from_private(const Key *k) | 93 | key_from_private(const Key *k) |
1371 | { | 94 | { |
1372 | Key *n = NULL; | 95 | int r; |
1373 | switch (k->type) { | 96 | Key *ret = NULL; |
1374 | #ifdef WITH_OPENSSL | ||
1375 | case KEY_DSA: | ||
1376 | case KEY_DSA_CERT_V00: | ||
1377 | case KEY_DSA_CERT: | ||
1378 | n = key_new(k->type); | ||
1379 | if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) || | ||
1380 | (BN_copy(n->dsa->q, k->dsa->q) == NULL) || | ||
1381 | (BN_copy(n->dsa->g, k->dsa->g) == NULL) || | ||
1382 | (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL)) | ||
1383 | fatal("key_from_private: BN_copy failed"); | ||
1384 | break; | ||
1385 | #ifdef OPENSSL_HAS_ECC | ||
1386 | case KEY_ECDSA: | ||
1387 | case KEY_ECDSA_CERT: | ||
1388 | n = key_new(k->type); | ||
1389 | n->ecdsa_nid = k->ecdsa_nid; | ||
1390 | if ((n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid)) == NULL) | ||
1391 | fatal("%s: EC_KEY_new_by_curve_name failed", __func__); | ||
1392 | if (EC_KEY_set_public_key(n->ecdsa, | ||
1393 | EC_KEY_get0_public_key(k->ecdsa)) != 1) | ||
1394 | fatal("%s: EC_KEY_set_public_key failed", __func__); | ||
1395 | break; | ||
1396 | #endif | ||
1397 | case KEY_RSA: | ||
1398 | case KEY_RSA1: | ||
1399 | case KEY_RSA_CERT_V00: | ||
1400 | case KEY_RSA_CERT: | ||
1401 | n = key_new(k->type); | ||
1402 | if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) || | ||
1403 | (BN_copy(n->rsa->e, k->rsa->e) == NULL)) | ||
1404 | fatal("key_from_private: BN_copy failed"); | ||
1405 | break; | ||
1406 | #endif | ||
1407 | case KEY_ED25519: | ||
1408 | case KEY_ED25519_CERT: | ||
1409 | n = key_new(k->type); | ||
1410 | if (k->ed25519_pk != NULL) { | ||
1411 | n->ed25519_pk = xmalloc(ED25519_PK_SZ); | ||
1412 | memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); | ||
1413 | } | ||
1414 | break; | ||
1415 | default: | ||
1416 | fatal("key_from_private: unknown type %d", k->type); | ||
1417 | break; | ||
1418 | } | ||
1419 | if (key_is_cert(k)) | ||
1420 | key_cert_copy(k, n); | ||
1421 | return n; | ||
1422 | } | ||
1423 | |||
1424 | int | ||
1425 | key_names_valid2(const char *names) | ||
1426 | { | ||
1427 | char *s, *cp, *p; | ||
1428 | |||
1429 | if (names == NULL || strcmp(names, "") == 0) | ||
1430 | return 0; | ||
1431 | s = cp = xstrdup(names); | ||
1432 | for ((p = strsep(&cp, ",")); p && *p != '\0'; | ||
1433 | (p = strsep(&cp, ","))) { | ||
1434 | switch (key_type_from_name(p)) { | ||
1435 | case KEY_RSA1: | ||
1436 | case KEY_UNSPEC: | ||
1437 | free(s); | ||
1438 | return 0; | ||
1439 | } | ||
1440 | } | ||
1441 | debug3("key names ok: [%s]", names); | ||
1442 | free(s); | ||
1443 | return 1; | ||
1444 | } | ||
1445 | |||
1446 | static int | ||
1447 | cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen) | ||
1448 | { | ||
1449 | u_char *principals, *critical, *exts, *sig_key, *sig; | ||
1450 | u_int signed_len, plen, clen, sklen, slen, kidlen, elen; | ||
1451 | Buffer tmp; | ||
1452 | char *principal; | ||
1453 | int ret = -1; | ||
1454 | int v00 = key->type == KEY_DSA_CERT_V00 || | ||
1455 | key->type == KEY_RSA_CERT_V00; | ||
1456 | |||
1457 | buffer_init(&tmp); | ||
1458 | |||
1459 | /* Copy the entire key blob for verification and later serialisation */ | ||
1460 | buffer_append(&key->cert->certblob, blob, blen); | ||
1461 | |||
1462 | elen = 0; /* Not touched for v00 certs */ | ||
1463 | principals = exts = critical = sig_key = sig = NULL; | ||
1464 | if ((!v00 && buffer_get_int64_ret(&key->cert->serial, b) != 0) || | ||
1465 | buffer_get_int_ret(&key->cert->type, b) != 0 || | ||
1466 | (key->cert->key_id = buffer_get_cstring_ret(b, &kidlen)) == NULL || | ||
1467 | (principals = buffer_get_string_ret(b, &plen)) == NULL || | ||
1468 | buffer_get_int64_ret(&key->cert->valid_after, b) != 0 || | ||
1469 | buffer_get_int64_ret(&key->cert->valid_before, b) != 0 || | ||
1470 | (critical = buffer_get_string_ret(b, &clen)) == NULL || | ||
1471 | (!v00 && (exts = buffer_get_string_ret(b, &elen)) == NULL) || | ||
1472 | (v00 && buffer_get_string_ptr_ret(b, NULL) == NULL) || /* nonce */ | ||
1473 | buffer_get_string_ptr_ret(b, NULL) == NULL || /* reserved */ | ||
1474 | (sig_key = buffer_get_string_ret(b, &sklen)) == NULL) { | ||
1475 | error("%s: parse error", __func__); | ||
1476 | goto out; | ||
1477 | } | ||
1478 | |||
1479 | /* Signature is left in the buffer so we can calculate this length */ | ||
1480 | signed_len = buffer_len(&key->cert->certblob) - buffer_len(b); | ||
1481 | |||
1482 | if ((sig = buffer_get_string_ret(b, &slen)) == NULL) { | ||
1483 | error("%s: parse error", __func__); | ||
1484 | goto out; | ||
1485 | } | ||
1486 | |||
1487 | if (key->cert->type != SSH2_CERT_TYPE_USER && | ||
1488 | key->cert->type != SSH2_CERT_TYPE_HOST) { | ||
1489 | error("Unknown certificate type %u", key->cert->type); | ||
1490 | goto out; | ||
1491 | } | ||
1492 | |||
1493 | buffer_append(&tmp, principals, plen); | ||
1494 | while (buffer_len(&tmp) > 0) { | ||
1495 | if (key->cert->nprincipals >= CERT_MAX_PRINCIPALS) { | ||
1496 | error("%s: Too many principals", __func__); | ||
1497 | goto out; | ||
1498 | } | ||
1499 | if ((principal = buffer_get_cstring_ret(&tmp, &plen)) == NULL) { | ||
1500 | error("%s: Principals data invalid", __func__); | ||
1501 | goto out; | ||
1502 | } | ||
1503 | key->cert->principals = xrealloc(key->cert->principals, | ||
1504 | key->cert->nprincipals + 1, sizeof(*key->cert->principals)); | ||
1505 | key->cert->principals[key->cert->nprincipals++] = principal; | ||
1506 | } | ||
1507 | |||
1508 | buffer_clear(&tmp); | ||
1509 | |||
1510 | buffer_append(&key->cert->critical, critical, clen); | ||
1511 | buffer_append(&tmp, critical, clen); | ||
1512 | /* validate structure */ | ||
1513 | while (buffer_len(&tmp) != 0) { | ||
1514 | if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL || | ||
1515 | buffer_get_string_ptr_ret(&tmp, NULL) == NULL) { | ||
1516 | error("%s: critical option data invalid", __func__); | ||
1517 | goto out; | ||
1518 | } | ||
1519 | } | ||
1520 | buffer_clear(&tmp); | ||
1521 | |||
1522 | buffer_append(&key->cert->extensions, exts, elen); | ||
1523 | buffer_append(&tmp, exts, elen); | ||
1524 | /* validate structure */ | ||
1525 | while (buffer_len(&tmp) != 0) { | ||
1526 | if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL || | ||
1527 | buffer_get_string_ptr_ret(&tmp, NULL) == NULL) { | ||
1528 | error("%s: extension data invalid", __func__); | ||
1529 | goto out; | ||
1530 | } | ||
1531 | } | ||
1532 | buffer_clear(&tmp); | ||
1533 | |||
1534 | if ((key->cert->signature_key = key_from_blob2(sig_key, sklen, 0)) | ||
1535 | == NULL) { | ||
1536 | error("%s: Signature key invalid", __func__); | ||
1537 | goto out; | ||
1538 | } | ||
1539 | if (!key_type_is_valid_ca(key->cert->signature_key->type)) { | ||
1540 | error("%s: Invalid signature key type %s (%d)", __func__, | ||
1541 | key_type(key->cert->signature_key), | ||
1542 | key->cert->signature_key->type); | ||
1543 | goto out; | ||
1544 | } | ||
1545 | 97 | ||
1546 | switch (key_verify(key->cert->signature_key, sig, slen, | 98 | if ((r = sshkey_from_private(k, &ret)) != 0) |
1547 | buffer_ptr(&key->cert->certblob), signed_len)) { | 99 | fatal("%s: %s", __func__, ssh_err(r)); |
1548 | case 1: | ||
1549 | ret = 0; | ||
1550 | break; /* Good signature */ | ||
1551 | case 0: | ||
1552 | error("%s: Invalid signature on certificate", __func__); | ||
1553 | goto out; | ||
1554 | case -1: | ||
1555 | error("%s: Certificate signature verification failed", | ||
1556 | __func__); | ||
1557 | goto out; | ||
1558 | } | ||
1559 | |||
1560 | out: | ||
1561 | buffer_free(&tmp); | ||
1562 | free(principals); | ||
1563 | free(critical); | ||
1564 | free(exts); | ||
1565 | free(sig_key); | ||
1566 | free(sig); | ||
1567 | return ret; | 100 | return ret; |
1568 | } | 101 | } |
1569 | 102 | ||
1570 | static Key * | 103 | static void |
1571 | key_from_blob2(const u_char *blob, u_int blen, int allow_cert) | 104 | fatal_on_fatal_errors(int r, const char *func, int extra_fatal) |
1572 | { | 105 | { |
1573 | Buffer b; | 106 | if (r == SSH_ERR_INTERNAL_ERROR || |
1574 | int rlen, type; | 107 | r == SSH_ERR_ALLOC_FAIL || |
1575 | u_int len; | 108 | (extra_fatal != 0 && r == extra_fatal)) |
1576 | char *ktype = NULL, *curve = NULL; | 109 | fatal("%s: %s", func, ssh_err(r)); |
1577 | u_char *pk = NULL; | ||
1578 | Key *key = NULL; | ||
1579 | #ifdef OPENSSL_HAS_ECC | ||
1580 | EC_POINT *q = NULL; | ||
1581 | int nid = -1; | ||
1582 | #endif | ||
1583 | |||
1584 | #ifdef DEBUG_PK | ||
1585 | dump_base64(stderr, blob, blen); | ||
1586 | #endif | ||
1587 | buffer_init(&b); | ||
1588 | buffer_append(&b, blob, blen); | ||
1589 | if ((ktype = buffer_get_cstring_ret(&b, NULL)) == NULL) { | ||
1590 | error("key_from_blob: can't read key type"); | ||
1591 | goto out; | ||
1592 | } | ||
1593 | |||
1594 | type = key_type_from_name(ktype); | ||
1595 | #ifdef OPENSSL_HAS_ECC | ||
1596 | if (key_type_plain(type) == KEY_ECDSA) | ||
1597 | nid = key_ecdsa_nid_from_name(ktype); | ||
1598 | #endif | ||
1599 | if (!allow_cert && key_type_is_cert(type)) { | ||
1600 | error("key_from_blob: certificate not allowed in this context"); | ||
1601 | goto out; | ||
1602 | } | ||
1603 | switch (type) { | ||
1604 | #ifdef WITH_OPENSSL | ||
1605 | case KEY_RSA_CERT: | ||
1606 | (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */ | ||
1607 | /* FALLTHROUGH */ | ||
1608 | case KEY_RSA: | ||
1609 | case KEY_RSA_CERT_V00: | ||
1610 | key = key_new(type); | ||
1611 | if (buffer_get_bignum2_ret(&b, key->rsa->e) == -1 || | ||
1612 | buffer_get_bignum2_ret(&b, key->rsa->n) == -1) { | ||
1613 | error("key_from_blob: can't read rsa key"); | ||
1614 | goto badkey; | ||
1615 | } | ||
1616 | #ifdef DEBUG_PK | ||
1617 | RSA_print_fp(stderr, key->rsa, 8); | ||
1618 | #endif | ||
1619 | break; | ||
1620 | case KEY_DSA_CERT: | ||
1621 | (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */ | ||
1622 | /* FALLTHROUGH */ | ||
1623 | case KEY_DSA: | ||
1624 | case KEY_DSA_CERT_V00: | ||
1625 | key = key_new(type); | ||
1626 | if (buffer_get_bignum2_ret(&b, key->dsa->p) == -1 || | ||
1627 | buffer_get_bignum2_ret(&b, key->dsa->q) == -1 || | ||
1628 | buffer_get_bignum2_ret(&b, key->dsa->g) == -1 || | ||
1629 | buffer_get_bignum2_ret(&b, key->dsa->pub_key) == -1) { | ||
1630 | error("key_from_blob: can't read dsa key"); | ||
1631 | goto badkey; | ||
1632 | } | ||
1633 | #ifdef DEBUG_PK | ||
1634 | DSA_print_fp(stderr, key->dsa, 8); | ||
1635 | #endif | ||
1636 | break; | ||
1637 | #ifdef OPENSSL_HAS_ECC | ||
1638 | case KEY_ECDSA_CERT: | ||
1639 | (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */ | ||
1640 | /* FALLTHROUGH */ | ||
1641 | case KEY_ECDSA: | ||
1642 | key = key_new(type); | ||
1643 | key->ecdsa_nid = nid; | ||
1644 | if ((curve = buffer_get_string_ret(&b, NULL)) == NULL) { | ||
1645 | error("key_from_blob: can't read ecdsa curve"); | ||
1646 | goto badkey; | ||
1647 | } | ||
1648 | if (key->ecdsa_nid != key_curve_name_to_nid(curve)) { | ||
1649 | error("key_from_blob: ecdsa curve doesn't match type"); | ||
1650 | goto badkey; | ||
1651 | } | ||
1652 | if (key->ecdsa != NULL) | ||
1653 | EC_KEY_free(key->ecdsa); | ||
1654 | if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid)) | ||
1655 | == NULL) | ||
1656 | fatal("key_from_blob: EC_KEY_new_by_curve_name failed"); | ||
1657 | if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL) | ||
1658 | fatal("key_from_blob: EC_POINT_new failed"); | ||
1659 | if (buffer_get_ecpoint_ret(&b, EC_KEY_get0_group(key->ecdsa), | ||
1660 | q) == -1) { | ||
1661 | error("key_from_blob: can't read ecdsa key point"); | ||
1662 | goto badkey; | ||
1663 | } | ||
1664 | if (key_ec_validate_public(EC_KEY_get0_group(key->ecdsa), | ||
1665 | q) != 0) | ||
1666 | goto badkey; | ||
1667 | if (EC_KEY_set_public_key(key->ecdsa, q) != 1) | ||
1668 | fatal("key_from_blob: EC_KEY_set_public_key failed"); | ||
1669 | #ifdef DEBUG_PK | ||
1670 | key_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q); | ||
1671 | #endif | ||
1672 | break; | ||
1673 | #endif /* OPENSSL_HAS_ECC */ | ||
1674 | case KEY_ED25519_CERT: | ||
1675 | (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */ | ||
1676 | /* FALLTHROUGH */ | ||
1677 | case KEY_ED25519: | ||
1678 | if ((pk = buffer_get_string_ret(&b, &len)) == NULL) { | ||
1679 | error("key_from_blob: can't read ed25519 key"); | ||
1680 | goto badkey; | ||
1681 | } | ||
1682 | if (len != ED25519_PK_SZ) { | ||
1683 | error("key_from_blob: ed25519 len %d != %d", | ||
1684 | len, ED25519_PK_SZ); | ||
1685 | goto badkey; | ||
1686 | } | ||
1687 | key = key_new(type); | ||
1688 | key->ed25519_pk = pk; | ||
1689 | pk = NULL; | ||
1690 | break; | ||
1691 | case KEY_UNSPEC: | ||
1692 | key = key_new(type); | ||
1693 | break; | ||
1694 | default: | ||
1695 | error("key_from_blob: cannot handle type %s", ktype); | ||
1696 | goto out; | ||
1697 | } | ||
1698 | if (key_is_cert(key) && cert_parse(&b, key, blob, blen) == -1) { | ||
1699 | error("key_from_blob: can't parse cert data"); | ||
1700 | goto badkey; | ||
1701 | } | ||
1702 | rlen = buffer_len(&b); | ||
1703 | if (key != NULL && rlen != 0) | ||
1704 | error("key_from_blob: remaining bytes in key blob %d", rlen); | ||
1705 | out: | ||
1706 | free(ktype); | ||
1707 | free(curve); | ||
1708 | free(pk); | ||
1709 | #ifdef OPENSSL_HAS_ECC | ||
1710 | if (q != NULL) | ||
1711 | EC_POINT_free(q); | ||
1712 | #endif | ||
1713 | buffer_free(&b); | ||
1714 | return key; | ||
1715 | |||
1716 | badkey: | ||
1717 | key_free(key); | ||
1718 | key = NULL; | ||
1719 | goto out; | ||
1720 | } | 110 | } |
1721 | 111 | ||
1722 | Key * | 112 | Key * |
1723 | key_from_blob(const u_char *blob, u_int blen) | 113 | key_from_blob(const u_char *blob, u_int blen) |
1724 | { | 114 | { |
1725 | return key_from_blob2(blob, blen, 1); | 115 | int r; |
116 | Key *ret = NULL; | ||
117 | |||
118 | if ((r = sshkey_from_blob(blob, blen, &ret)) != 0) { | ||
119 | fatal_on_fatal_errors(r, __func__, 0); | ||
120 | error("%s: %s", __func__, ssh_err(r)); | ||
121 | return NULL; | ||
122 | } | ||
123 | return ret; | ||
1726 | } | 124 | } |
1727 | 125 | ||
1728 | static int | 126 | int |
1729 | to_blob(const Key *key, u_char **blobp, u_int *lenp, int force_plain) | 127 | key_to_blob(const Key *key, u_char **blobp, u_int *lenp) |
1730 | { | 128 | { |
1731 | Buffer b; | 129 | u_char *blob; |
1732 | int len, type; | 130 | size_t blen; |
131 | int r; | ||
1733 | 132 | ||
1734 | if (blobp != NULL) | 133 | if (blobp != NULL) |
1735 | *blobp = NULL; | 134 | *blobp = NULL; |
1736 | if (lenp != NULL) | 135 | if (lenp != NULL) |
1737 | *lenp = 0; | 136 | *lenp = 0; |
1738 | if (key == NULL) { | 137 | if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) { |
1739 | error("key_to_blob: key == NULL"); | 138 | fatal_on_fatal_errors(r, __func__, 0); |
139 | error("%s: %s", __func__, ssh_err(r)); | ||
1740 | return 0; | 140 | return 0; |
1741 | } | 141 | } |
1742 | buffer_init(&b); | 142 | if (blen > INT_MAX) |
1743 | type = force_plain ? key_type_plain(key->type) : key->type; | 143 | fatal("%s: giant len %zu", __func__, blen); |
1744 | switch (type) { | 144 | if (blobp != NULL) |
1745 | #ifdef WITH_OPENSSL | 145 | *blobp = blob; |
1746 | case KEY_DSA_CERT_V00: | ||
1747 | case KEY_RSA_CERT_V00: | ||
1748 | case KEY_DSA_CERT: | ||
1749 | case KEY_ECDSA_CERT: | ||
1750 | case KEY_RSA_CERT: | ||
1751 | #endif | ||
1752 | case KEY_ED25519_CERT: | ||
1753 | /* Use the existing blob */ | ||
1754 | buffer_append(&b, buffer_ptr(&key->cert->certblob), | ||
1755 | buffer_len(&key->cert->certblob)); | ||
1756 | break; | ||
1757 | #ifdef WITH_OPENSSL | ||
1758 | case KEY_DSA: | ||
1759 | buffer_put_cstring(&b, | ||
1760 | key_ssh_name_from_type_nid(type, key->ecdsa_nid)); | ||
1761 | buffer_put_bignum2(&b, key->dsa->p); | ||
1762 | buffer_put_bignum2(&b, key->dsa->q); | ||
1763 | buffer_put_bignum2(&b, key->dsa->g); | ||
1764 | buffer_put_bignum2(&b, key->dsa->pub_key); | ||
1765 | break; | ||
1766 | #ifdef OPENSSL_HAS_ECC | ||
1767 | case KEY_ECDSA: | ||
1768 | buffer_put_cstring(&b, | ||
1769 | key_ssh_name_from_type_nid(type, key->ecdsa_nid)); | ||
1770 | buffer_put_cstring(&b, key_curve_nid_to_name(key->ecdsa_nid)); | ||
1771 | buffer_put_ecpoint(&b, EC_KEY_get0_group(key->ecdsa), | ||
1772 | EC_KEY_get0_public_key(key->ecdsa)); | ||
1773 | break; | ||
1774 | #endif | ||
1775 | case KEY_RSA: | ||
1776 | buffer_put_cstring(&b, | ||
1777 | key_ssh_name_from_type_nid(type, key->ecdsa_nid)); | ||
1778 | buffer_put_bignum2(&b, key->rsa->e); | ||
1779 | buffer_put_bignum2(&b, key->rsa->n); | ||
1780 | break; | ||
1781 | #endif | ||
1782 | case KEY_ED25519: | ||
1783 | buffer_put_cstring(&b, | ||
1784 | key_ssh_name_from_type_nid(type, key->ecdsa_nid)); | ||
1785 | buffer_put_string(&b, key->ed25519_pk, ED25519_PK_SZ); | ||
1786 | break; | ||
1787 | default: | ||
1788 | error("key_to_blob: unsupported key type %d", key->type); | ||
1789 | buffer_free(&b); | ||
1790 | return 0; | ||
1791 | } | ||
1792 | len = buffer_len(&b); | ||
1793 | if (lenp != NULL) | 146 | if (lenp != NULL) |
1794 | *lenp = len; | 147 | *lenp = blen; |
1795 | if (blobp != NULL) { | 148 | return blen; |
1796 | *blobp = xmalloc(len); | ||
1797 | memcpy(*blobp, buffer_ptr(&b), len); | ||
1798 | } | ||
1799 | explicit_bzero(buffer_ptr(&b), len); | ||
1800 | buffer_free(&b); | ||
1801 | return len; | ||
1802 | } | 149 | } |
1803 | 150 | ||
1804 | int | 151 | int |
1805 | key_to_blob(const Key *key, u_char **blobp, u_int *lenp) | 152 | key_sign(const Key *key, u_char **sigp, u_int *lenp, |
1806 | { | ||
1807 | return to_blob(key, blobp, lenp, 0); | ||
1808 | } | ||
1809 | |||
1810 | int | ||
1811 | key_sign( | ||
1812 | const Key *key, | ||
1813 | u_char **sigp, u_int *lenp, | ||
1814 | const u_char *data, u_int datalen) | 153 | const u_char *data, u_int datalen) |
1815 | { | 154 | { |
1816 | switch (key->type) { | 155 | int r; |
1817 | #ifdef WITH_OPENSSL | 156 | u_char *sig; |
1818 | case KEY_DSA_CERT_V00: | 157 | size_t siglen; |
1819 | case KEY_DSA_CERT: | 158 | |
1820 | case KEY_DSA: | 159 | if (sigp != NULL) |
1821 | return ssh_dss_sign(key, sigp, lenp, data, datalen); | 160 | *sigp = NULL; |
1822 | #ifdef OPENSSL_HAS_ECC | 161 | if (lenp != NULL) |
1823 | case KEY_ECDSA_CERT: | 162 | *lenp = 0; |
1824 | case KEY_ECDSA: | 163 | if ((r = sshkey_sign(key, &sig, &siglen, |
1825 | return ssh_ecdsa_sign(key, sigp, lenp, data, datalen); | 164 | data, datalen, datafellows)) != 0) { |
1826 | #endif | 165 | fatal_on_fatal_errors(r, __func__, 0); |
1827 | case KEY_RSA_CERT_V00: | 166 | error("%s: %s", __func__, ssh_err(r)); |
1828 | case KEY_RSA_CERT: | ||
1829 | case KEY_RSA: | ||
1830 | return ssh_rsa_sign(key, sigp, lenp, data, datalen); | ||
1831 | #endif | ||
1832 | case KEY_ED25519: | ||
1833 | case KEY_ED25519_CERT: | ||
1834 | return ssh_ed25519_sign(key, sigp, lenp, data, datalen); | ||
1835 | default: | ||
1836 | error("key_sign: invalid key type %d", key->type); | ||
1837 | return -1; | 167 | return -1; |
1838 | } | 168 | } |
169 | if (siglen > INT_MAX) | ||
170 | fatal("%s: giant len %zu", __func__, siglen); | ||
171 | if (sigp != NULL) | ||
172 | *sigp = sig; | ||
173 | if (lenp != NULL) | ||
174 | *lenp = siglen; | ||
175 | return 0; | ||
1839 | } | 176 | } |
1840 | 177 | ||
1841 | /* | ||
1842 | * key_verify returns 1 for a correct signature, 0 for an incorrect signature | ||
1843 | * and -1 on error. | ||
1844 | */ | ||
1845 | int | 178 | int |
1846 | key_verify( | 179 | key_verify(const Key *key, const u_char *signature, u_int signaturelen, |
1847 | const Key *key, | ||
1848 | const u_char *signature, u_int signaturelen, | ||
1849 | const u_char *data, u_int datalen) | 180 | const u_char *data, u_int datalen) |
1850 | { | 181 | { |
1851 | if (signaturelen == 0) | 182 | int r; |
1852 | return -1; | ||
1853 | 183 | ||
1854 | switch (key->type) { | 184 | if ((r = sshkey_verify(key, signature, signaturelen, |
1855 | #ifdef WITH_OPENSSL | 185 | data, datalen, datafellows)) != 0) { |
1856 | case KEY_DSA_CERT_V00: | 186 | fatal_on_fatal_errors(r, __func__, 0); |
1857 | case KEY_DSA_CERT: | 187 | error("%s: %s", __func__, ssh_err(r)); |
1858 | case KEY_DSA: | 188 | return r == SSH_ERR_SIGNATURE_INVALID ? 0 : -1; |
1859 | return ssh_dss_verify(key, signature, signaturelen, data, datalen); | ||
1860 | #ifdef OPENSSL_HAS_ECC | ||
1861 | case KEY_ECDSA_CERT: | ||
1862 | case KEY_ECDSA: | ||
1863 | return ssh_ecdsa_verify(key, signature, signaturelen, data, datalen); | ||
1864 | #endif | ||
1865 | case KEY_RSA_CERT_V00: | ||
1866 | case KEY_RSA_CERT: | ||
1867 | case KEY_RSA: | ||
1868 | return ssh_rsa_verify(key, signature, signaturelen, data, datalen); | ||
1869 | #endif | ||
1870 | case KEY_ED25519: | ||
1871 | case KEY_ED25519_CERT: | ||
1872 | return ssh_ed25519_verify(key, signature, signaturelen, data, datalen); | ||
1873 | default: | ||
1874 | error("key_verify: invalid key type %d", key->type); | ||
1875 | return -1; | ||
1876 | } | 189 | } |
190 | return 1; | ||
1877 | } | 191 | } |
1878 | 192 | ||
1879 | /* Converts a private to a public key */ | ||
1880 | Key * | 193 | Key * |
1881 | key_demote(const Key *k) | 194 | key_demote(const Key *k) |
1882 | { | 195 | { |
1883 | Key *pk; | 196 | int r; |
1884 | 197 | Key *ret = NULL; | |
1885 | pk = xcalloc(1, sizeof(*pk)); | ||
1886 | pk->type = k->type; | ||
1887 | pk->flags = k->flags; | ||
1888 | pk->ecdsa_nid = k->ecdsa_nid; | ||
1889 | pk->dsa = NULL; | ||
1890 | pk->ecdsa = NULL; | ||
1891 | pk->rsa = NULL; | ||
1892 | pk->ed25519_pk = NULL; | ||
1893 | pk->ed25519_sk = NULL; | ||
1894 | |||
1895 | switch (k->type) { | ||
1896 | #ifdef WITH_OPENSSL | ||
1897 | case KEY_RSA_CERT_V00: | ||
1898 | case KEY_RSA_CERT: | ||
1899 | key_cert_copy(k, pk); | ||
1900 | /* FALLTHROUGH */ | ||
1901 | case KEY_RSA1: | ||
1902 | case KEY_RSA: | ||
1903 | if ((pk->rsa = RSA_new()) == NULL) | ||
1904 | fatal("key_demote: RSA_new failed"); | ||
1905 | if ((pk->rsa->e = BN_dup(k->rsa->e)) == NULL) | ||
1906 | fatal("key_demote: BN_dup failed"); | ||
1907 | if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL) | ||
1908 | fatal("key_demote: BN_dup failed"); | ||
1909 | break; | ||
1910 | case KEY_DSA_CERT_V00: | ||
1911 | case KEY_DSA_CERT: | ||
1912 | key_cert_copy(k, pk); | ||
1913 | /* FALLTHROUGH */ | ||
1914 | case KEY_DSA: | ||
1915 | if ((pk->dsa = DSA_new()) == NULL) | ||
1916 | fatal("key_demote: DSA_new failed"); | ||
1917 | if ((pk->dsa->p = BN_dup(k->dsa->p)) == NULL) | ||
1918 | fatal("key_demote: BN_dup failed"); | ||
1919 | if ((pk->dsa->q = BN_dup(k->dsa->q)) == NULL) | ||
1920 | fatal("key_demote: BN_dup failed"); | ||
1921 | if ((pk->dsa->g = BN_dup(k->dsa->g)) == NULL) | ||
1922 | fatal("key_demote: BN_dup failed"); | ||
1923 | if ((pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) | ||
1924 | fatal("key_demote: BN_dup failed"); | ||
1925 | break; | ||
1926 | #ifdef OPENSSL_HAS_ECC | ||
1927 | case KEY_ECDSA_CERT: | ||
1928 | key_cert_copy(k, pk); | ||
1929 | /* FALLTHROUGH */ | ||
1930 | case KEY_ECDSA: | ||
1931 | if ((pk->ecdsa = EC_KEY_new_by_curve_name(pk->ecdsa_nid)) == NULL) | ||
1932 | fatal("key_demote: EC_KEY_new_by_curve_name failed"); | ||
1933 | if (EC_KEY_set_public_key(pk->ecdsa, | ||
1934 | EC_KEY_get0_public_key(k->ecdsa)) != 1) | ||
1935 | fatal("key_demote: EC_KEY_set_public_key failed"); | ||
1936 | break; | ||
1937 | #endif | ||
1938 | case KEY_ED25519_CERT: | ||
1939 | key_cert_copy(k, pk); | ||
1940 | /* FALLTHROUGH */ | ||
1941 | case KEY_ED25519: | ||
1942 | if (k->ed25519_pk != NULL) { | ||
1943 | pk->ed25519_pk = xmalloc(ED25519_PK_SZ); | ||
1944 | memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); | ||
1945 | } | ||
1946 | break; | ||
1947 | default: | ||
1948 | fatal("key_demote: bad key type %d", k->type); | ||
1949 | break; | ||
1950 | } | ||
1951 | |||
1952 | return (pk); | ||
1953 | } | ||
1954 | |||
1955 | int | ||
1956 | key_is_cert(const Key *k) | ||
1957 | { | ||
1958 | if (k == NULL) | ||
1959 | return 0; | ||
1960 | return key_type_is_cert(k->type); | ||
1961 | } | ||
1962 | 198 | ||
1963 | /* Return the cert-less equivalent to a certified key type */ | 199 | if ((r = sshkey_demote(k, &ret)) != 0) |
1964 | int | 200 | fatal("%s: %s", __func__, ssh_err(r)); |
1965 | key_type_plain(int type) | 201 | return ret; |
1966 | { | ||
1967 | switch (type) { | ||
1968 | case KEY_RSA_CERT_V00: | ||
1969 | case KEY_RSA_CERT: | ||
1970 | return KEY_RSA; | ||
1971 | case KEY_DSA_CERT_V00: | ||
1972 | case KEY_DSA_CERT: | ||
1973 | return KEY_DSA; | ||
1974 | case KEY_ECDSA_CERT: | ||
1975 | return KEY_ECDSA; | ||
1976 | case KEY_ED25519_CERT: | ||
1977 | return KEY_ED25519; | ||
1978 | default: | ||
1979 | return type; | ||
1980 | } | ||
1981 | } | 202 | } |
1982 | 203 | ||
1983 | /* Convert a plain key to their _CERT equivalent */ | ||
1984 | int | 204 | int |
1985 | key_to_certified(Key *k, int legacy) | 205 | key_to_certified(Key *k, int legacy) |
1986 | { | 206 | { |
1987 | switch (k->type) { | 207 | int r; |
1988 | case KEY_RSA: | 208 | |
1989 | k->cert = cert_new(); | 209 | if ((r = sshkey_to_certified(k, legacy)) != 0) { |
1990 | k->type = legacy ? KEY_RSA_CERT_V00 : KEY_RSA_CERT; | 210 | fatal_on_fatal_errors(r, __func__, 0); |
1991 | return 0; | 211 | error("%s: %s", __func__, ssh_err(r)); |
1992 | case KEY_DSA: | ||
1993 | k->cert = cert_new(); | ||
1994 | k->type = legacy ? KEY_DSA_CERT_V00 : KEY_DSA_CERT; | ||
1995 | return 0; | ||
1996 | case KEY_ECDSA: | ||
1997 | if (legacy) | ||
1998 | fatal("%s: legacy ECDSA certificates are not supported", | ||
1999 | __func__); | ||
2000 | k->cert = cert_new(); | ||
2001 | k->type = KEY_ECDSA_CERT; | ||
2002 | return 0; | ||
2003 | case KEY_ED25519: | ||
2004 | if (legacy) | ||
2005 | fatal("%s: legacy ED25519 certificates are not " | ||
2006 | "supported", __func__); | ||
2007 | k->cert = cert_new(); | ||
2008 | k->type = KEY_ED25519_CERT; | ||
2009 | return 0; | ||
2010 | default: | ||
2011 | error("%s: key has incorrect type %s", __func__, key_type(k)); | ||
2012 | return -1; | 212 | return -1; |
2013 | } | 213 | } |
214 | return 0; | ||
2014 | } | 215 | } |
2015 | 216 | ||
2016 | /* Convert a certificate to its raw key equivalent */ | ||
2017 | int | 217 | int |
2018 | key_drop_cert(Key *k) | 218 | key_drop_cert(Key *k) |
2019 | { | 219 | { |
2020 | if (!key_type_is_cert(k->type)) { | 220 | int r; |
2021 | error("%s: key has incorrect type %s", __func__, key_type(k)); | 221 | |
222 | if ((r = sshkey_drop_cert(k)) != 0) { | ||
223 | fatal_on_fatal_errors(r, __func__, 0); | ||
224 | error("%s: %s", __func__, ssh_err(r)); | ||
2022 | return -1; | 225 | return -1; |
2023 | } | 226 | } |
2024 | cert_free(k->cert); | ||
2025 | k->cert = NULL; | ||
2026 | k->type = key_type_plain(k->type); | ||
2027 | return 0; | 227 | return 0; |
2028 | } | 228 | } |
2029 | 229 | ||
2030 | /* Sign a certified key, (re-)generating the signed certblob. */ | ||
2031 | int | 230 | int |
2032 | key_certify(Key *k, Key *ca) | 231 | key_certify(Key *k, Key *ca) |
2033 | { | 232 | { |
2034 | Buffer principals; | 233 | int r; |
2035 | u_char *ca_blob, *sig_blob, nonce[32]; | ||
2036 | u_int i, ca_len, sig_len; | ||
2037 | 234 | ||
2038 | if (k->cert == NULL) { | 235 | if ((r = sshkey_certify(k, ca)) != 0) { |
2039 | error("%s: key lacks cert info", __func__); | 236 | fatal_on_fatal_errors(r, __func__, 0); |
237 | error("%s: %s", __func__, ssh_err(r)); | ||
2040 | return -1; | 238 | return -1; |
2041 | } | 239 | } |
240 | return 0; | ||
241 | } | ||
2042 | 242 | ||
2043 | if (!key_is_cert(k)) { | 243 | int |
2044 | error("%s: certificate has unknown type %d", __func__, | 244 | key_cert_check_authority(const Key *k, int want_host, int require_principal, |
2045 | k->cert->type); | 245 | const char *name, const char **reason) |
2046 | return -1; | 246 | { |
2047 | } | 247 | int r; |
2048 | 248 | ||
2049 | if (!key_type_is_valid_ca(ca->type)) { | 249 | if ((r = sshkey_cert_check_authority(k, want_host, require_principal, |
2050 | error("%s: CA key has unsupported type %s", __func__, | 250 | name, reason)) != 0) { |
2051 | key_type(ca)); | 251 | fatal_on_fatal_errors(r, __func__, 0); |
252 | error("%s: %s", __func__, ssh_err(r)); | ||
2052 | return -1; | 253 | return -1; |
2053 | } | 254 | } |
255 | return 0; | ||
256 | } | ||
2054 | 257 | ||
2055 | key_to_blob(ca, &ca_blob, &ca_len); | ||
2056 | |||
2057 | buffer_clear(&k->cert->certblob); | ||
2058 | buffer_put_cstring(&k->cert->certblob, key_ssh_name(k)); | ||
2059 | |||
2060 | /* -v01 certs put nonce first */ | ||
2061 | arc4random_buf(&nonce, sizeof(nonce)); | ||
2062 | if (!key_cert_is_legacy(k)) | ||
2063 | buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce)); | ||
2064 | |||
2065 | /* XXX this substantially duplicates to_blob(); refactor */ | ||
2066 | switch (k->type) { | ||
2067 | #ifdef WITH_OPENSSL | 258 | #ifdef WITH_OPENSSL |
2068 | case KEY_DSA_CERT_V00: | 259 | int |
2069 | case KEY_DSA_CERT: | 260 | key_ec_validate_public(const EC_GROUP *group, const EC_POINT *public) |
2070 | buffer_put_bignum2(&k->cert->certblob, k->dsa->p); | 261 | { |
2071 | buffer_put_bignum2(&k->cert->certblob, k->dsa->q); | 262 | int r; |
2072 | buffer_put_bignum2(&k->cert->certblob, k->dsa->g); | ||
2073 | buffer_put_bignum2(&k->cert->certblob, k->dsa->pub_key); | ||
2074 | break; | ||
2075 | #ifdef OPENSSL_HAS_ECC | ||
2076 | case KEY_ECDSA_CERT: | ||
2077 | buffer_put_cstring(&k->cert->certblob, | ||
2078 | key_curve_nid_to_name(k->ecdsa_nid)); | ||
2079 | buffer_put_ecpoint(&k->cert->certblob, | ||
2080 | EC_KEY_get0_group(k->ecdsa), | ||
2081 | EC_KEY_get0_public_key(k->ecdsa)); | ||
2082 | break; | ||
2083 | #endif | ||
2084 | case KEY_RSA_CERT_V00: | ||
2085 | case KEY_RSA_CERT: | ||
2086 | buffer_put_bignum2(&k->cert->certblob, k->rsa->e); | ||
2087 | buffer_put_bignum2(&k->cert->certblob, k->rsa->n); | ||
2088 | break; | ||
2089 | #endif | ||
2090 | case KEY_ED25519_CERT: | ||
2091 | buffer_put_string(&k->cert->certblob, | ||
2092 | k->ed25519_pk, ED25519_PK_SZ); | ||
2093 | break; | ||
2094 | default: | ||
2095 | error("%s: key has incorrect type %s", __func__, key_type(k)); | ||
2096 | buffer_clear(&k->cert->certblob); | ||
2097 | free(ca_blob); | ||
2098 | return -1; | ||
2099 | } | ||
2100 | |||
2101 | /* -v01 certs have a serial number next */ | ||
2102 | if (!key_cert_is_legacy(k)) | ||
2103 | buffer_put_int64(&k->cert->certblob, k->cert->serial); | ||
2104 | |||
2105 | buffer_put_int(&k->cert->certblob, k->cert->type); | ||
2106 | buffer_put_cstring(&k->cert->certblob, k->cert->key_id); | ||
2107 | |||
2108 | buffer_init(&principals); | ||
2109 | for (i = 0; i < k->cert->nprincipals; i++) | ||
2110 | buffer_put_cstring(&principals, k->cert->principals[i]); | ||
2111 | buffer_put_string(&k->cert->certblob, buffer_ptr(&principals), | ||
2112 | buffer_len(&principals)); | ||
2113 | buffer_free(&principals); | ||
2114 | |||
2115 | buffer_put_int64(&k->cert->certblob, k->cert->valid_after); | ||
2116 | buffer_put_int64(&k->cert->certblob, k->cert->valid_before); | ||
2117 | buffer_put_string(&k->cert->certblob, | ||
2118 | buffer_ptr(&k->cert->critical), buffer_len(&k->cert->critical)); | ||
2119 | |||
2120 | /* -v01 certs have non-critical options here */ | ||
2121 | if (!key_cert_is_legacy(k)) { | ||
2122 | buffer_put_string(&k->cert->certblob, | ||
2123 | buffer_ptr(&k->cert->extensions), | ||
2124 | buffer_len(&k->cert->extensions)); | ||
2125 | } | ||
2126 | |||
2127 | /* -v00 certs put the nonce at the end */ | ||
2128 | if (key_cert_is_legacy(k)) | ||
2129 | buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce)); | ||
2130 | |||
2131 | buffer_put_string(&k->cert->certblob, NULL, 0); /* reserved */ | ||
2132 | buffer_put_string(&k->cert->certblob, ca_blob, ca_len); | ||
2133 | free(ca_blob); | ||
2134 | 263 | ||
2135 | /* Sign the whole mess */ | 264 | if ((r = sshkey_ec_validate_public(group, public)) != 0) { |
2136 | if (key_sign(ca, &sig_blob, &sig_len, buffer_ptr(&k->cert->certblob), | 265 | fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
2137 | buffer_len(&k->cert->certblob)) != 0) { | 266 | error("%s: %s", __func__, ssh_err(r)); |
2138 | error("%s: signature operation failed", __func__); | ||
2139 | buffer_clear(&k->cert->certblob); | ||
2140 | return -1; | 267 | return -1; |
2141 | } | 268 | } |
2142 | /* Append signature and we are done */ | ||
2143 | buffer_put_string(&k->cert->certblob, sig_blob, sig_len); | ||
2144 | free(sig_blob); | ||
2145 | |||
2146 | return 0; | 269 | return 0; |
2147 | } | 270 | } |
2148 | 271 | ||
2149 | int | 272 | int |
2150 | key_cert_check_authority(const Key *k, int want_host, int require_principal, | 273 | key_ec_validate_private(const EC_KEY *key) |
2151 | const char *name, const char **reason) | ||
2152 | { | 274 | { |
2153 | u_int i, principal_matches; | 275 | int r; |
2154 | time_t now = time(NULL); | 276 | |
2155 | 277 | if ((r = sshkey_ec_validate_private(key)) != 0) { | |
2156 | if (want_host) { | 278 | fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
2157 | if (k->cert->type != SSH2_CERT_TYPE_HOST) { | 279 | error("%s: %s", __func__, ssh_err(r)); |
2158 | *reason = "Certificate invalid: not a host certificate"; | ||
2159 | return -1; | ||
2160 | } | ||
2161 | } else { | ||
2162 | if (k->cert->type != SSH2_CERT_TYPE_USER) { | ||
2163 | *reason = "Certificate invalid: not a user certificate"; | ||
2164 | return -1; | ||
2165 | } | ||
2166 | } | ||
2167 | if (now < 0) { | ||
2168 | error("%s: system clock lies before epoch", __func__); | ||
2169 | *reason = "Certificate invalid: not yet valid"; | ||
2170 | return -1; | ||
2171 | } | ||
2172 | if ((u_int64_t)now < k->cert->valid_after) { | ||
2173 | *reason = "Certificate invalid: not yet valid"; | ||
2174 | return -1; | ||
2175 | } | ||
2176 | if ((u_int64_t)now >= k->cert->valid_before) { | ||
2177 | *reason = "Certificate invalid: expired"; | ||
2178 | return -1; | 280 | return -1; |
2179 | } | 281 | } |
2180 | if (k->cert->nprincipals == 0) { | ||
2181 | if (require_principal) { | ||
2182 | *reason = "Certificate lacks principal list"; | ||
2183 | return -1; | ||
2184 | } | ||
2185 | } else if (name != NULL) { | ||
2186 | principal_matches = 0; | ||
2187 | for (i = 0; i < k->cert->nprincipals; i++) { | ||
2188 | if (strcmp(name, k->cert->principals[i]) == 0) { | ||
2189 | principal_matches = 1; | ||
2190 | break; | ||
2191 | } | ||
2192 | } | ||
2193 | if (!principal_matches) { | ||
2194 | *reason = "Certificate invalid: name is not a listed " | ||
2195 | "principal"; | ||
2196 | return -1; | ||
2197 | } | ||
2198 | } | ||
2199 | return 0; | 282 | return 0; |
2200 | } | 283 | } |
284 | #endif /* WITH_OPENSSL */ | ||
2201 | 285 | ||
2202 | int | 286 | void |
2203 | key_cert_is_legacy(const Key *k) | 287 | key_private_serialize(const Key *key, struct sshbuf *b) |
2204 | { | 288 | { |
2205 | switch (k->type) { | 289 | int r; |
2206 | case KEY_DSA_CERT_V00: | ||
2207 | case KEY_RSA_CERT_V00: | ||
2208 | return 1; | ||
2209 | default: | ||
2210 | return 0; | ||
2211 | } | ||
2212 | } | ||
2213 | 290 | ||
2214 | #ifdef WITH_OPENSSL | 291 | if ((r = sshkey_private_serialize(key, b)) != 0) |
2215 | /* XXX: these are really begging for a table-driven approach */ | 292 | fatal("%s: %s", __func__, ssh_err(r)); |
2216 | int | ||
2217 | key_curve_name_to_nid(const char *name) | ||
2218 | { | ||
2219 | #ifdef OPENSSL_HAS_ECC | ||
2220 | if (strcmp(name, "nistp256") == 0) | ||
2221 | return NID_X9_62_prime256v1; | ||
2222 | else if (strcmp(name, "nistp384") == 0) | ||
2223 | return NID_secp384r1; | ||
2224 | # ifdef OPENSSL_HAS_NISTP521 | ||
2225 | else if (strcmp(name, "nistp521") == 0) | ||
2226 | return NID_secp521r1; | ||
2227 | # endif | ||
2228 | #endif | ||
2229 | |||
2230 | debug("%s: unsupported EC curve name \"%.100s\"", __func__, name); | ||
2231 | return -1; | ||
2232 | } | 293 | } |
2233 | 294 | ||
2234 | u_int | 295 | Key * |
2235 | key_curve_nid_to_bits(int nid) | 296 | key_private_deserialize(struct sshbuf *blob) |
2236 | { | 297 | { |
2237 | switch (nid) { | 298 | int r; |
2238 | #ifdef OPENSSL_HAS_ECC | 299 | Key *ret = NULL; |
2239 | case NID_X9_62_prime256v1: | 300 | |
2240 | return 256; | 301 | if ((r = sshkey_private_deserialize(blob, &ret)) != 0) { |
2241 | case NID_secp384r1: | 302 | fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
2242 | return 384; | 303 | error("%s: %s", __func__, ssh_err(r)); |
2243 | # ifdef OPENSSL_HAS_NISTP521 | 304 | return NULL; |
2244 | case NID_secp521r1: | ||
2245 | return 521; | ||
2246 | # endif | ||
2247 | #endif | ||
2248 | default: | ||
2249 | error("%s: unsupported EC curve nid %d", __func__, nid); | ||
2250 | return 0; | ||
2251 | } | 305 | } |
306 | return ret; | ||
2252 | } | 307 | } |
2253 | 308 | ||
2254 | const char * | 309 | /* authfile.c */ |
2255 | key_curve_nid_to_name(int nid) | ||
2256 | { | ||
2257 | #ifdef OPENSSL_HAS_ECC | ||
2258 | if (nid == NID_X9_62_prime256v1) | ||
2259 | return "nistp256"; | ||
2260 | else if (nid == NID_secp384r1) | ||
2261 | return "nistp384"; | ||
2262 | # ifdef OPENSSL_HAS_NISTP521 | ||
2263 | else if (nid == NID_secp521r1) | ||
2264 | return "nistp521"; | ||
2265 | # endif | ||
2266 | #endif | ||
2267 | error("%s: unsupported EC curve nid %d", __func__, nid); | ||
2268 | return NULL; | ||
2269 | } | ||
2270 | 310 | ||
2271 | #ifdef OPENSSL_HAS_ECC | ||
2272 | int | 311 | int |
2273 | key_ec_nid_to_hash_alg(int nid) | 312 | key_save_private(Key *key, const char *filename, const char *passphrase, |
313 | const char *comment, int force_new_format, const char *new_format_cipher, | ||
314 | int new_format_rounds) | ||
2274 | { | 315 | { |
2275 | int kbits = key_curve_nid_to_bits(nid); | 316 | int r; |
2276 | 317 | ||
2277 | if (kbits == 0) | 318 | if ((r = sshkey_save_private(key, filename, passphrase, comment, |
2278 | fatal("%s: invalid nid %d", __func__, nid); | 319 | force_new_format, new_format_cipher, new_format_rounds)) != 0) { |
2279 | /* RFC5656 section 6.2.1 */ | 320 | fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
2280 | if (kbits <= 256) | 321 | error("%s: %s", __func__, ssh_err(r)); |
2281 | return SSH_DIGEST_SHA256; | 322 | return 0; |
2282 | else if (kbits <= 384) | 323 | } |
2283 | return SSH_DIGEST_SHA384; | 324 | return 1; |
2284 | else | ||
2285 | return SSH_DIGEST_SHA512; | ||
2286 | } | 325 | } |
2287 | 326 | ||
2288 | int | 327 | int |
2289 | key_ec_validate_public(const EC_GROUP *group, const EC_POINT *public) | 328 | key_load_file(int fd, const char *filename, struct sshbuf *blob) |
2290 | { | 329 | { |
2291 | BN_CTX *bnctx; | 330 | int r; |
2292 | EC_POINT *nq = NULL; | ||
2293 | BIGNUM *order, *x, *y, *tmp; | ||
2294 | int ret = -1; | ||
2295 | |||
2296 | if ((bnctx = BN_CTX_new()) == NULL) | ||
2297 | fatal("%s: BN_CTX_new failed", __func__); | ||
2298 | BN_CTX_start(bnctx); | ||
2299 | |||
2300 | /* | ||
2301 | * We shouldn't ever hit this case because bignum_get_ecpoint() | ||
2302 | * refuses to load GF2m points. | ||
2303 | */ | ||
2304 | if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != | ||
2305 | NID_X9_62_prime_field) { | ||
2306 | error("%s: group is not a prime field", __func__); | ||
2307 | goto out; | ||
2308 | } | ||
2309 | |||
2310 | /* Q != infinity */ | ||
2311 | if (EC_POINT_is_at_infinity(group, public)) { | ||
2312 | error("%s: received degenerate public key (infinity)", | ||
2313 | __func__); | ||
2314 | goto out; | ||
2315 | } | ||
2316 | 331 | ||
2317 | if ((x = BN_CTX_get(bnctx)) == NULL || | 332 | if ((r = sshkey_load_file(fd, filename, blob)) != 0) { |
2318 | (y = BN_CTX_get(bnctx)) == NULL || | 333 | fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
2319 | (order = BN_CTX_get(bnctx)) == NULL || | 334 | error("%s: %s", __func__, ssh_err(r)); |
2320 | (tmp = BN_CTX_get(bnctx)) == NULL) | 335 | return 0; |
2321 | fatal("%s: BN_CTX_get failed", __func__); | ||
2322 | |||
2323 | /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */ | ||
2324 | if (EC_GROUP_get_order(group, order, bnctx) != 1) | ||
2325 | fatal("%s: EC_GROUP_get_order failed", __func__); | ||
2326 | if (EC_POINT_get_affine_coordinates_GFp(group, public, | ||
2327 | x, y, bnctx) != 1) | ||
2328 | fatal("%s: EC_POINT_get_affine_coordinates_GFp", __func__); | ||
2329 | if (BN_num_bits(x) <= BN_num_bits(order) / 2) { | ||
2330 | error("%s: public key x coordinate too small: " | ||
2331 | "bits(x) = %d, bits(order)/2 = %d", __func__, | ||
2332 | BN_num_bits(x), BN_num_bits(order) / 2); | ||
2333 | goto out; | ||
2334 | } | ||
2335 | if (BN_num_bits(y) <= BN_num_bits(order) / 2) { | ||
2336 | error("%s: public key y coordinate too small: " | ||
2337 | "bits(y) = %d, bits(order)/2 = %d", __func__, | ||
2338 | BN_num_bits(x), BN_num_bits(order) / 2); | ||
2339 | goto out; | ||
2340 | } | 336 | } |
337 | return 1; | ||
338 | } | ||
2341 | 339 | ||
2342 | /* nQ == infinity (n == order of subgroup) */ | 340 | Key * |
2343 | if ((nq = EC_POINT_new(group)) == NULL) | 341 | key_load_cert(const char *filename) |
2344 | fatal("%s: BN_CTX_tmp failed", __func__); | 342 | { |
2345 | if (EC_POINT_mul(group, nq, NULL, public, order, bnctx) != 1) | 343 | int r; |
2346 | fatal("%s: EC_GROUP_mul failed", __func__); | 344 | Key *ret = NULL; |
2347 | if (EC_POINT_is_at_infinity(group, nq) != 1) { | ||
2348 | error("%s: received degenerate public key (nQ != infinity)", | ||
2349 | __func__); | ||
2350 | goto out; | ||
2351 | } | ||
2352 | 345 | ||
2353 | /* x < order - 1, y < order - 1 */ | 346 | if ((r = sshkey_load_cert(filename, &ret)) != 0) { |
2354 | if (!BN_sub(tmp, order, BN_value_one())) | 347 | fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
2355 | fatal("%s: BN_sub failed", __func__); | 348 | if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) |
2356 | if (BN_cmp(x, tmp) >= 0) { | 349 | debug("%s: %s", __func__, ssh_err(r)); |
2357 | error("%s: public key x coordinate >= group order - 1", | 350 | else |
2358 | __func__); | 351 | error("%s: %s", __func__, ssh_err(r)); |
2359 | goto out; | 352 | return NULL; |
2360 | } | ||
2361 | if (BN_cmp(y, tmp) >= 0) { | ||
2362 | error("%s: public key y coordinate >= group order - 1", | ||
2363 | __func__); | ||
2364 | goto out; | ||
2365 | } | 353 | } |
2366 | ret = 0; | ||
2367 | out: | ||
2368 | BN_CTX_free(bnctx); | ||
2369 | EC_POINT_free(nq); | ||
2370 | return ret; | 354 | return ret; |
355 | |||
2371 | } | 356 | } |
2372 | 357 | ||
2373 | int | 358 | Key * |
2374 | key_ec_validate_private(const EC_KEY *key) | 359 | key_load_public(const char *filename, char **commentp) |
2375 | { | 360 | { |
2376 | BN_CTX *bnctx; | 361 | int r; |
2377 | BIGNUM *order, *tmp; | 362 | Key *ret = NULL; |
2378 | int ret = -1; | ||
2379 | |||
2380 | if ((bnctx = BN_CTX_new()) == NULL) | ||
2381 | fatal("%s: BN_CTX_new failed", __func__); | ||
2382 | BN_CTX_start(bnctx); | ||
2383 | |||
2384 | if ((order = BN_CTX_get(bnctx)) == NULL || | ||
2385 | (tmp = BN_CTX_get(bnctx)) == NULL) | ||
2386 | fatal("%s: BN_CTX_get failed", __func__); | ||
2387 | |||
2388 | /* log2(private) > log2(order)/2 */ | ||
2389 | if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, bnctx) != 1) | ||
2390 | fatal("%s: EC_GROUP_get_order failed", __func__); | ||
2391 | if (BN_num_bits(EC_KEY_get0_private_key(key)) <= | ||
2392 | BN_num_bits(order) / 2) { | ||
2393 | error("%s: private key too small: " | ||
2394 | "bits(y) = %d, bits(order)/2 = %d", __func__, | ||
2395 | BN_num_bits(EC_KEY_get0_private_key(key)), | ||
2396 | BN_num_bits(order) / 2); | ||
2397 | goto out; | ||
2398 | } | ||
2399 | 363 | ||
2400 | /* private < order - 1 */ | 364 | if ((r = sshkey_load_public(filename, &ret, commentp)) != 0) { |
2401 | if (!BN_sub(tmp, order, BN_value_one())) | 365 | fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
2402 | fatal("%s: BN_sub failed", __func__); | 366 | if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) |
2403 | if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0) { | 367 | debug("%s: %s", __func__, ssh_err(r)); |
2404 | error("%s: private key >= group order - 1", __func__); | 368 | else |
2405 | goto out; | 369 | error("%s: %s", __func__, ssh_err(r)); |
370 | return NULL; | ||
2406 | } | 371 | } |
2407 | ret = 0; | ||
2408 | out: | ||
2409 | BN_CTX_free(bnctx); | ||
2410 | return ret; | 372 | return ret; |
2411 | } | 373 | } |
2412 | #endif | ||
2413 | 374 | ||
2414 | #if defined(DEBUG_KEXECDH) || defined(DEBUG_PK) | 375 | Key * |
2415 | void | 376 | key_load_private(const char *path, const char *passphrase, |
2416 | key_dump_ec_point(const EC_GROUP *group, const EC_POINT *point) | 377 | char **commentp) |
2417 | { | 378 | { |
2418 | BIGNUM *x, *y; | 379 | int r; |
2419 | BN_CTX *bnctx; | 380 | Key *ret = NULL; |
2420 | 381 | ||
2421 | if (point == NULL) { | 382 | if ((r = sshkey_load_private(path, passphrase, &ret, commentp)) != 0) { |
2422 | fputs("point=(NULL)\n", stderr); | 383 | fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
2423 | return; | 384 | if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) |
385 | debug("%s: %s", __func__, ssh_err(r)); | ||
386 | else | ||
387 | error("%s: %s", __func__, ssh_err(r)); | ||
388 | return NULL; | ||
2424 | } | 389 | } |
2425 | if ((bnctx = BN_CTX_new()) == NULL) | 390 | return ret; |
2426 | fatal("%s: BN_CTX_new failed", __func__); | ||
2427 | BN_CTX_start(bnctx); | ||
2428 | if ((x = BN_CTX_get(bnctx)) == NULL || (y = BN_CTX_get(bnctx)) == NULL) | ||
2429 | fatal("%s: BN_CTX_get failed", __func__); | ||
2430 | if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != | ||
2431 | NID_X9_62_prime_field) | ||
2432 | fatal("%s: group is not a prime field", __func__); | ||
2433 | if (EC_POINT_get_affine_coordinates_GFp(group, point, x, y, bnctx) != 1) | ||
2434 | fatal("%s: EC_POINT_get_affine_coordinates_GFp", __func__); | ||
2435 | fputs("x=", stderr); | ||
2436 | BN_print_fp(stderr, x); | ||
2437 | fputs("\ny=", stderr); | ||
2438 | BN_print_fp(stderr, y); | ||
2439 | fputs("\n", stderr); | ||
2440 | BN_CTX_free(bnctx); | ||
2441 | } | 391 | } |
2442 | 392 | ||
2443 | void | 393 | Key * |
2444 | key_dump_ec_key(const EC_KEY *key) | 394 | key_load_private_cert(int type, const char *filename, const char *passphrase, |
2445 | { | 395 | int *perm_ok) |
2446 | const BIGNUM *exponent; | 396 | { |
2447 | 397 | int r; | |
2448 | key_dump_ec_point(EC_KEY_get0_group(key), EC_KEY_get0_public_key(key)); | 398 | Key *ret = NULL; |
2449 | fputs("exponent=", stderr); | 399 | |
2450 | if ((exponent = EC_KEY_get0_private_key(key)) == NULL) | 400 | if ((r = sshkey_load_private_cert(type, filename, passphrase, |
2451 | fputs("(NULL)", stderr); | 401 | &ret, perm_ok)) != 0) { |
2452 | else | 402 | fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
2453 | BN_print_fp(stderr, EC_KEY_get0_private_key(key)); | 403 | if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) |
2454 | fputs("\n", stderr); | 404 | debug("%s: %s", __func__, ssh_err(r)); |
405 | else | ||
406 | error("%s: %s", __func__, ssh_err(r)); | ||
407 | return NULL; | ||
408 | } | ||
409 | return ret; | ||
2455 | } | 410 | } |
2456 | #endif /* defined(DEBUG_KEXECDH) || defined(DEBUG_PK) */ | ||
2457 | #endif /* OPENSSL_HAS_ECC */ | ||
2458 | 411 | ||
2459 | void | 412 | Key * |
2460 | key_private_serialize(const Key *key, Buffer *b) | 413 | key_load_private_type(int type, const char *filename, const char *passphrase, |
2461 | { | 414 | char **commentp, int *perm_ok) |
2462 | buffer_put_cstring(b, key_ssh_name(key)); | 415 | { |
2463 | switch (key->type) { | 416 | int r; |
2464 | #ifdef WITH_OPENSSL | 417 | Key *ret = NULL; |
2465 | case KEY_RSA: | 418 | |
2466 | buffer_put_bignum2(b, key->rsa->n); | 419 | if ((r = sshkey_load_private_type(type, filename, passphrase, |
2467 | buffer_put_bignum2(b, key->rsa->e); | 420 | &ret, commentp, perm_ok)) != 0) { |
2468 | buffer_put_bignum2(b, key->rsa->d); | 421 | fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
2469 | buffer_put_bignum2(b, key->rsa->iqmp); | 422 | if ((r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) || |
2470 | buffer_put_bignum2(b, key->rsa->p); | 423 | (r == SSH_ERR_KEY_WRONG_PASSPHRASE)) |
2471 | buffer_put_bignum2(b, key->rsa->q); | 424 | debug("%s: %s", __func__, ssh_err(r)); |
2472 | break; | 425 | else |
2473 | case KEY_RSA_CERT_V00: | 426 | error("%s: %s", __func__, ssh_err(r)); |
2474 | case KEY_RSA_CERT: | 427 | return NULL; |
2475 | if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0) | ||
2476 | fatal("%s: no cert/certblob", __func__); | ||
2477 | buffer_put_string(b, buffer_ptr(&key->cert->certblob), | ||
2478 | buffer_len(&key->cert->certblob)); | ||
2479 | buffer_put_bignum2(b, key->rsa->d); | ||
2480 | buffer_put_bignum2(b, key->rsa->iqmp); | ||
2481 | buffer_put_bignum2(b, key->rsa->p); | ||
2482 | buffer_put_bignum2(b, key->rsa->q); | ||
2483 | break; | ||
2484 | case KEY_DSA: | ||
2485 | buffer_put_bignum2(b, key->dsa->p); | ||
2486 | buffer_put_bignum2(b, key->dsa->q); | ||
2487 | buffer_put_bignum2(b, key->dsa->g); | ||
2488 | buffer_put_bignum2(b, key->dsa->pub_key); | ||
2489 | buffer_put_bignum2(b, key->dsa->priv_key); | ||
2490 | break; | ||
2491 | case KEY_DSA_CERT_V00: | ||
2492 | case KEY_DSA_CERT: | ||
2493 | if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0) | ||
2494 | fatal("%s: no cert/certblob", __func__); | ||
2495 | buffer_put_string(b, buffer_ptr(&key->cert->certblob), | ||
2496 | buffer_len(&key->cert->certblob)); | ||
2497 | buffer_put_bignum2(b, key->dsa->priv_key); | ||
2498 | break; | ||
2499 | #ifdef OPENSSL_HAS_ECC | ||
2500 | case KEY_ECDSA: | ||
2501 | buffer_put_cstring(b, key_curve_nid_to_name(key->ecdsa_nid)); | ||
2502 | buffer_put_ecpoint(b, EC_KEY_get0_group(key->ecdsa), | ||
2503 | EC_KEY_get0_public_key(key->ecdsa)); | ||
2504 | buffer_put_bignum2(b, EC_KEY_get0_private_key(key->ecdsa)); | ||
2505 | break; | ||
2506 | case KEY_ECDSA_CERT: | ||
2507 | if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0) | ||
2508 | fatal("%s: no cert/certblob", __func__); | ||
2509 | buffer_put_string(b, buffer_ptr(&key->cert->certblob), | ||
2510 | buffer_len(&key->cert->certblob)); | ||
2511 | buffer_put_bignum2(b, EC_KEY_get0_private_key(key->ecdsa)); | ||
2512 | break; | ||
2513 | #endif /* OPENSSL_HAS_ECC */ | ||
2514 | case KEY_ED25519: | ||
2515 | buffer_put_string(b, key->ed25519_pk, ED25519_PK_SZ); | ||
2516 | buffer_put_string(b, key->ed25519_sk, ED25519_SK_SZ); | ||
2517 | break; | ||
2518 | #endif | ||
2519 | #endif | ||
2520 | case KEY_ED25519_CERT: | ||
2521 | if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0) | ||
2522 | fatal("%s: no cert/certblob", __func__); | ||
2523 | buffer_put_string(b, buffer_ptr(&key->cert->certblob), | ||
2524 | buffer_len(&key->cert->certblob)); | ||
2525 | buffer_put_string(b, key->ed25519_pk, ED25519_PK_SZ); | ||
2526 | buffer_put_string(b, key->ed25519_sk, ED25519_SK_SZ); | ||
2527 | break; | ||
2528 | } | 428 | } |
429 | return ret; | ||
2529 | } | 430 | } |
2530 | 431 | ||
432 | #ifdef WITH_OPENSSL | ||
2531 | Key * | 433 | Key * |
2532 | key_private_deserialize(Buffer *blob) | 434 | key_load_private_pem(int fd, int type, const char *passphrase, |
435 | char **commentp) | ||
2533 | { | 436 | { |
2534 | char *type_name; | 437 | int r; |
2535 | Key *k = NULL; | 438 | Key *ret = NULL; |
2536 | u_char *cert; | 439 | |
2537 | u_int len, pklen, sklen; | 440 | if ((r = sshkey_load_private_pem(fd, type, passphrase, |
2538 | int type; | 441 | &ret, commentp)) != 0) { |
2539 | #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) | 442 | fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
2540 | char *curve; | 443 | error("%s: %s", __func__, ssh_err(r)); |
2541 | BIGNUM *exponent; | ||
2542 | EC_POINT *q; | ||
2543 | #endif | ||
2544 | |||
2545 | type_name = buffer_get_string(blob, NULL); | ||
2546 | type = key_type_from_name(type_name); | ||
2547 | switch (type) { | ||
2548 | #ifdef WITH_OPENSSL | ||
2549 | case KEY_DSA: | ||
2550 | k = key_new_private(type); | ||
2551 | buffer_get_bignum2(blob, k->dsa->p); | ||
2552 | buffer_get_bignum2(blob, k->dsa->q); | ||
2553 | buffer_get_bignum2(blob, k->dsa->g); | ||
2554 | buffer_get_bignum2(blob, k->dsa->pub_key); | ||
2555 | buffer_get_bignum2(blob, k->dsa->priv_key); | ||
2556 | break; | ||
2557 | case KEY_DSA_CERT_V00: | ||
2558 | case KEY_DSA_CERT: | ||
2559 | cert = buffer_get_string(blob, &len); | ||
2560 | if ((k = key_from_blob(cert, len)) == NULL) | ||
2561 | fatal("Certificate parse failed"); | ||
2562 | free(cert); | ||
2563 | key_add_private(k); | ||
2564 | buffer_get_bignum2(blob, k->dsa->priv_key); | ||
2565 | break; | ||
2566 | #ifdef OPENSSL_HAS_ECC | ||
2567 | case KEY_ECDSA: | ||
2568 | k = key_new_private(type); | ||
2569 | k->ecdsa_nid = key_ecdsa_nid_from_name(type_name); | ||
2570 | curve = buffer_get_string(blob, NULL); | ||
2571 | if (k->ecdsa_nid != key_curve_name_to_nid(curve)) | ||
2572 | fatal("%s: curve names mismatch", __func__); | ||
2573 | free(curve); | ||
2574 | k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid); | ||
2575 | if (k->ecdsa == NULL) | ||
2576 | fatal("%s: EC_KEY_new_by_curve_name failed", | ||
2577 | __func__); | ||
2578 | q = EC_POINT_new(EC_KEY_get0_group(k->ecdsa)); | ||
2579 | if (q == NULL) | ||
2580 | fatal("%s: BN_new failed", __func__); | ||
2581 | if ((exponent = BN_new()) == NULL) | ||
2582 | fatal("%s: BN_new failed", __func__); | ||
2583 | buffer_get_ecpoint(blob, | ||
2584 | EC_KEY_get0_group(k->ecdsa), q); | ||
2585 | buffer_get_bignum2(blob, exponent); | ||
2586 | if (EC_KEY_set_public_key(k->ecdsa, q) != 1) | ||
2587 | fatal("%s: EC_KEY_set_public_key failed", | ||
2588 | __func__); | ||
2589 | if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) | ||
2590 | fatal("%s: EC_KEY_set_private_key failed", | ||
2591 | __func__); | ||
2592 | if (key_ec_validate_public(EC_KEY_get0_group(k->ecdsa), | ||
2593 | EC_KEY_get0_public_key(k->ecdsa)) != 0) | ||
2594 | fatal("%s: bad ECDSA public key", __func__); | ||
2595 | if (key_ec_validate_private(k->ecdsa) != 0) | ||
2596 | fatal("%s: bad ECDSA private key", __func__); | ||
2597 | BN_clear_free(exponent); | ||
2598 | EC_POINT_free(q); | ||
2599 | break; | ||
2600 | case KEY_ECDSA_CERT: | ||
2601 | cert = buffer_get_string(blob, &len); | ||
2602 | if ((k = key_from_blob(cert, len)) == NULL) | ||
2603 | fatal("Certificate parse failed"); | ||
2604 | free(cert); | ||
2605 | key_add_private(k); | ||
2606 | if ((exponent = BN_new()) == NULL) | ||
2607 | fatal("%s: BN_new failed", __func__); | ||
2608 | buffer_get_bignum2(blob, exponent); | ||
2609 | if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) | ||
2610 | fatal("%s: EC_KEY_set_private_key failed", | ||
2611 | __func__); | ||
2612 | if (key_ec_validate_public(EC_KEY_get0_group(k->ecdsa), | ||
2613 | EC_KEY_get0_public_key(k->ecdsa)) != 0 || | ||
2614 | key_ec_validate_private(k->ecdsa) != 0) | ||
2615 | fatal("%s: bad ECDSA key", __func__); | ||
2616 | BN_clear_free(exponent); | ||
2617 | break; | ||
2618 | #endif | ||
2619 | case KEY_RSA: | ||
2620 | k = key_new_private(type); | ||
2621 | buffer_get_bignum2(blob, k->rsa->n); | ||
2622 | buffer_get_bignum2(blob, k->rsa->e); | ||
2623 | buffer_get_bignum2(blob, k->rsa->d); | ||
2624 | buffer_get_bignum2(blob, k->rsa->iqmp); | ||
2625 | buffer_get_bignum2(blob, k->rsa->p); | ||
2626 | buffer_get_bignum2(blob, k->rsa->q); | ||
2627 | |||
2628 | /* Generate additional parameters */ | ||
2629 | rsa_generate_additional_parameters(k->rsa); | ||
2630 | break; | ||
2631 | case KEY_RSA_CERT_V00: | ||
2632 | case KEY_RSA_CERT: | ||
2633 | cert = buffer_get_string(blob, &len); | ||
2634 | if ((k = key_from_blob(cert, len)) == NULL) | ||
2635 | fatal("Certificate parse failed"); | ||
2636 | free(cert); | ||
2637 | key_add_private(k); | ||
2638 | buffer_get_bignum2(blob, k->rsa->d); | ||
2639 | buffer_get_bignum2(blob, k->rsa->iqmp); | ||
2640 | buffer_get_bignum2(blob, k->rsa->p); | ||
2641 | buffer_get_bignum2(blob, k->rsa->q); | ||
2642 | break; | ||
2643 | #endif | ||
2644 | #endif | ||
2645 | case KEY_ED25519: | ||
2646 | k = key_new_private(type); | ||
2647 | k->ed25519_pk = buffer_get_string(blob, &pklen); | ||
2648 | k->ed25519_sk = buffer_get_string(blob, &sklen); | ||
2649 | if (pklen != ED25519_PK_SZ) | ||
2650 | fatal("%s: ed25519 pklen %d != %d", | ||
2651 | __func__, pklen, ED25519_PK_SZ); | ||
2652 | if (sklen != ED25519_SK_SZ) | ||
2653 | fatal("%s: ed25519 sklen %d != %d", | ||
2654 | __func__, sklen, ED25519_SK_SZ); | ||
2655 | break; | ||
2656 | case KEY_ED25519_CERT: | ||
2657 | cert = buffer_get_string(blob, &len); | ||
2658 | if ((k = key_from_blob(cert, len)) == NULL) | ||
2659 | fatal("Certificate parse failed"); | ||
2660 | free(cert); | ||
2661 | key_add_private(k); | ||
2662 | k->ed25519_pk = buffer_get_string(blob, &pklen); | ||
2663 | k->ed25519_sk = buffer_get_string(blob, &sklen); | ||
2664 | if (pklen != ED25519_PK_SZ) | ||
2665 | fatal("%s: ed25519 pklen %d != %d", | ||
2666 | __func__, pklen, ED25519_PK_SZ); | ||
2667 | if (sklen != ED25519_SK_SZ) | ||
2668 | fatal("%s: ed25519 sklen %d != %d", | ||
2669 | __func__, sklen, ED25519_SK_SZ); | ||
2670 | break; | ||
2671 | default: | ||
2672 | free(type_name); | ||
2673 | buffer_clear(blob); | ||
2674 | return NULL; | 444 | return NULL; |
2675 | } | 445 | } |
2676 | free(type_name); | 446 | return ret; |
447 | } | ||
448 | #endif /* WITH_OPENSSL */ | ||
2677 | 449 | ||
2678 | /* enable blinding */ | 450 | int |
2679 | switch (k->type) { | 451 | key_perm_ok(int fd, const char *filename) |
2680 | #ifdef WITH_OPENSSL | 452 | { |
2681 | case KEY_RSA: | 453 | return sshkey_perm_ok(fd, filename) == 0 ? 1 : 0; |
2682 | case KEY_RSA_CERT_V00: | 454 | } |
2683 | case KEY_RSA_CERT: | 455 | |
2684 | case KEY_RSA1: | 456 | int |
2685 | if (RSA_blinding_on(k->rsa, NULL) != 1) { | 457 | key_in_file(Key *key, const char *filename, int strict_type) |
2686 | error("%s: RSA_blinding_on failed", __func__); | 458 | { |
2687 | key_free(k); | 459 | int r; |
2688 | return NULL; | 460 | |
2689 | } | 461 | if ((r = sshkey_in_file(key, filename, strict_type)) != 0) { |
2690 | break; | 462 | fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR); |
2691 | #endif | 463 | if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) |
464 | return 0; | ||
465 | error("%s: %s", __func__, ssh_err(r)); | ||
466 | return r == SSH_ERR_KEY_NOT_FOUND ? 0 : -1; | ||
2692 | } | 467 | } |
2693 | return k; | 468 | return 1; |
2694 | } | 469 | } |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: key.h,v 1.41 2014/01/09 23:20:00 djm Exp $ */ | 1 | /* $OpenBSD: key.h,v 1.42 2014/06/24 01:13:21 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
@@ -26,141 +26,86 @@ | |||
26 | #ifndef KEY_H | 26 | #ifndef KEY_H |
27 | #define KEY_H | 27 | #define KEY_H |
28 | 28 | ||
29 | #include "buffer.h" | 29 | #include "sshkey.h" |
30 | #include <openssl/rsa.h> | 30 | |
31 | #include <openssl/dsa.h> | 31 | typedef struct sshkey Key; |
32 | #ifdef OPENSSL_HAS_ECC | 32 | |
33 | #include <openssl/ec.h> | 33 | #define types sshkey_types |
34 | #define fp_type sshkey_fp_type | ||
35 | #define fp_rep sshkey_fp_rep | ||
36 | |||
37 | #ifndef SSH_KEY_NO_DEFINE | ||
38 | #define key_new sshkey_new | ||
39 | #define key_free sshkey_free | ||
40 | #define key_equal_public sshkey_equal_public | ||
41 | #define key_equal sshkey_equal | ||
42 | #define key_fingerprint sshkey_fingerprint | ||
43 | #define key_type sshkey_type | ||
44 | #define key_cert_type sshkey_cert_type | ||
45 | #define key_ssh_name sshkey_ssh_name | ||
46 | #define key_ssh_name_plain sshkey_ssh_name_plain | ||
47 | #define key_type_from_name sshkey_type_from_name | ||
48 | #define key_ecdsa_nid_from_name sshkey_ecdsa_nid_from_name | ||
49 | #define key_type_is_cert sshkey_type_is_cert | ||
50 | #define key_size sshkey_size | ||
51 | #define key_ecdsa_bits_to_nid sshkey_ecdsa_bits_to_nid | ||
52 | #define key_ecdsa_key_to_nid sshkey_ecdsa_key_to_nid | ||
53 | #define key_names_valid2 sshkey_names_valid2 | ||
54 | #define key_is_cert sshkey_is_cert | ||
55 | #define key_type_plain sshkey_type_plain | ||
56 | #define key_cert_is_legacy sshkey_cert_is_legacy | ||
57 | #define key_curve_name_to_nid sshkey_curve_name_to_nid | ||
58 | #define key_curve_nid_to_bits sshkey_curve_nid_to_bits | ||
59 | #define key_curve_nid_to_name sshkey_curve_nid_to_name | ||
60 | #define key_ec_nid_to_hash_alg sshkey_ec_nid_to_hash_alg | ||
61 | #define key_dump_ec_point sshkey_dump_ec_point | ||
62 | #define key_dump_ec_key sshkey_dump_ec_key | ||
63 | #define key_fingerprint sshkey_fingerprint | ||
34 | #endif | 64 | #endif |
35 | 65 | ||
36 | typedef struct Key Key; | 66 | void key_add_private(Key *); |
37 | enum types { | 67 | Key *key_new_private(int); |
38 | KEY_RSA1, | 68 | void key_free(Key *); |
39 | KEY_RSA, | 69 | Key *key_demote(const Key *); |
40 | KEY_DSA, | 70 | u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *); |
41 | KEY_ECDSA, | 71 | int key_write(const Key *, FILE *); |
42 | KEY_ED25519, | 72 | int key_read(Key *, char **); |
43 | KEY_RSA_CERT, | ||
44 | KEY_DSA_CERT, | ||
45 | KEY_ECDSA_CERT, | ||
46 | KEY_ED25519_CERT, | ||
47 | KEY_RSA_CERT_V00, | ||
48 | KEY_DSA_CERT_V00, | ||
49 | KEY_UNSPEC | ||
50 | }; | ||
51 | enum fp_type { | ||
52 | SSH_FP_SHA1, | ||
53 | SSH_FP_MD5, | ||
54 | SSH_FP_SHA256 | ||
55 | }; | ||
56 | enum fp_rep { | ||
57 | SSH_FP_HEX, | ||
58 | SSH_FP_BUBBLEBABBLE, | ||
59 | SSH_FP_RANDOMART | ||
60 | }; | ||
61 | |||
62 | /* key is stored in external hardware */ | ||
63 | #define KEY_FLAG_EXT 0x0001 | ||
64 | |||
65 | #define CERT_MAX_PRINCIPALS 256 | ||
66 | struct KeyCert { | ||
67 | Buffer certblob; /* Kept around for use on wire */ | ||
68 | u_int type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */ | ||
69 | u_int64_t serial; | ||
70 | char *key_id; | ||
71 | u_int nprincipals; | ||
72 | char **principals; | ||
73 | u_int64_t valid_after, valid_before; | ||
74 | Buffer critical; | ||
75 | Buffer extensions; | ||
76 | Key *signature_key; | ||
77 | }; | ||
78 | |||
79 | struct Key { | ||
80 | int type; | ||
81 | int flags; | ||
82 | RSA *rsa; | ||
83 | DSA *dsa; | ||
84 | int ecdsa_nid; /* NID of curve */ | ||
85 | #ifdef OPENSSL_HAS_ECC | ||
86 | EC_KEY *ecdsa; | ||
87 | #else | ||
88 | void *ecdsa; | ||
89 | #endif | ||
90 | struct KeyCert *cert; | ||
91 | u_char *ed25519_sk; | ||
92 | u_char *ed25519_pk; | ||
93 | }; | ||
94 | |||
95 | #define ED25519_SK_SZ crypto_sign_ed25519_SECRETKEYBYTES | ||
96 | #define ED25519_PK_SZ crypto_sign_ed25519_PUBLICKEYBYTES | ||
97 | |||
98 | Key *key_new(int); | ||
99 | void key_add_private(Key *); | ||
100 | Key *key_new_private(int); | ||
101 | void key_free(Key *); | ||
102 | Key *key_demote(const Key *); | ||
103 | int key_equal_public(const Key *, const Key *); | ||
104 | int key_equal(const Key *, const Key *); | ||
105 | char *key_fingerprint(const Key *, enum fp_type, enum fp_rep); | ||
106 | u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *); | ||
107 | const char *key_type(const Key *); | ||
108 | const char *key_cert_type(const Key *); | ||
109 | int key_write(const Key *, FILE *); | ||
110 | int key_read(Key *, char **); | ||
111 | u_int key_size(const Key *); | ||
112 | 73 | ||
113 | Key *key_generate(int, u_int); | 74 | Key *key_generate(int, u_int); |
114 | Key *key_from_private(const Key *); | 75 | Key *key_from_private(const Key *); |
115 | int key_type_from_name(char *); | ||
116 | int key_is_cert(const Key *); | ||
117 | int key_type_is_cert(int); | ||
118 | int key_type_plain(int); | ||
119 | int key_to_certified(Key *, int); | 76 | int key_to_certified(Key *, int); |
120 | int key_drop_cert(Key *); | 77 | int key_drop_cert(Key *); |
121 | int key_certify(Key *, Key *); | 78 | int key_certify(Key *, Key *); |
122 | void key_cert_copy(const Key *, struct Key *); | 79 | void key_cert_copy(const Key *, Key *); |
123 | int key_cert_check_authority(const Key *, int, int, const char *, | 80 | int key_cert_check_authority(const Key *, int, int, const char *, |
124 | const char **); | 81 | const char **); |
125 | int key_cert_is_legacy(const Key *); | 82 | char *key_alg_list(int, int); |
126 | 83 | ||
127 | int key_ecdsa_nid_from_name(const char *); | 84 | #ifdef WITH_OPENSSL |
128 | int key_curve_name_to_nid(const char *); | 85 | int key_ec_validate_public(const EC_GROUP *, const EC_POINT *); |
129 | const char *key_curve_nid_to_name(int); | 86 | int key_ec_validate_private(const EC_KEY *); |
130 | u_int key_curve_nid_to_bits(int); | 87 | #endif /* WITH_OPENSSL */ |
131 | int key_ecdsa_bits_to_nid(int); | ||
132 | #ifdef OPENSSL_HAS_ECC | ||
133 | int key_ecdsa_key_to_nid(EC_KEY *); | ||
134 | int key_ec_nid_to_hash_alg(int nid); | ||
135 | int key_ec_validate_public(const EC_GROUP *, const EC_POINT *); | ||
136 | int key_ec_validate_private(const EC_KEY *); | ||
137 | #endif | ||
138 | char *key_alg_list(int, int); | ||
139 | 88 | ||
140 | Key *key_from_blob(const u_char *, u_int); | 89 | Key *key_from_blob(const u_char *, u_int); |
141 | int key_to_blob(const Key *, u_char **, u_int *); | 90 | int key_to_blob(const Key *, u_char **, u_int *); |
142 | const char *key_ssh_name(const Key *); | ||
143 | const char *key_ssh_name_plain(const Key *); | ||
144 | int key_names_valid2(const char *); | ||
145 | 91 | ||
146 | int key_sign(const Key *, u_char **, u_int *, const u_char *, u_int); | 92 | int key_sign(const Key *, u_char **, u_int *, const u_char *, u_int); |
147 | int key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); | 93 | int key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); |
148 | 94 | ||
149 | int ssh_dss_sign(const Key *, u_char **, u_int *, const u_char *, u_int); | 95 | void key_private_serialize(const Key *, struct sshbuf *); |
150 | int ssh_dss_verify(const Key *, const u_char *, u_int, const u_char *, u_int); | 96 | Key *key_private_deserialize(struct sshbuf *); |
151 | int ssh_ecdsa_sign(const Key *, u_char **, u_int *, const u_char *, u_int); | 97 | |
152 | int ssh_ecdsa_verify(const Key *, const u_char *, u_int, const u_char *, u_int); | 98 | /* authfile.c */ |
153 | int ssh_rsa_sign(const Key *, u_char **, u_int *, const u_char *, u_int); | 99 | int key_save_private(Key *, const char *, const char *, const char *, |
154 | int ssh_rsa_verify(const Key *, const u_char *, u_int, const u_char *, u_int); | 100 | int, const char *, int); |
155 | int ssh_ed25519_sign(const Key *, u_char **, u_int *, const u_char *, u_int); | 101 | int key_load_file(int, const char *, struct sshbuf *); |
156 | int ssh_ed25519_verify(const Key *, const u_char *, u_int, const u_char *, u_int); | 102 | Key *key_load_cert(const char *); |
157 | 103 | Key *key_load_public(const char *, char **); | |
158 | #if defined(OPENSSL_HAS_ECC) && (defined(DEBUG_KEXECDH) || defined(DEBUG_PK)) | 104 | Key *key_load_private(const char *, const char *, char **); |
159 | void key_dump_ec_point(const EC_GROUP *, const EC_POINT *); | 105 | Key *key_load_private_cert(int, const char *, const char *, int *); |
160 | void key_dump_ec_key(const EC_KEY *); | 106 | Key *key_load_private_type(int, const char *, const char *, char **, int *); |
161 | #endif | 107 | Key *key_load_private_pem(int, int, const char *, char **); |
162 | 108 | int key_perm_ok(int, const char *); | |
163 | void key_private_serialize(const Key *, Buffer *); | 109 | int key_in_file(Key *, const char *, int); |
164 | Key *key_private_deserialize(Buffer *); | ||
165 | 110 | ||
166 | #endif | 111 | #endif |
@@ -14,7 +14,7 @@ | |||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | /* $OpenBSD: krl.c,v 1.16 2014/06/24 00:52:02 djm Exp $ */ | 17 | /* $OpenBSD: krl.c,v 1.17 2014/06/24 01:13:21 djm Exp $ */ |
18 | 18 | ||
19 | #include "includes.h" | 19 | #include "includes.h" |
20 | 20 | ||
@@ -366,7 +366,7 @@ plain_key_blob(const Key *key, u_char **blob, u_int *blen) | |||
366 | } | 366 | } |
367 | r = key_to_blob(kcopy, blob, blen); | 367 | r = key_to_blob(kcopy, blob, blen); |
368 | free(kcopy); | 368 | free(kcopy); |
369 | return r == 0 ? -1 : 0; | 369 | return r; |
370 | } | 370 | } |
371 | 371 | ||
372 | /* Revoke a key blob. Ownership of blob is transferred to the tree */ | 372 | /* Revoke a key blob. Ownership of blob is transferred to the tree */ |
@@ -394,7 +394,7 @@ ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const Key *key) | |||
394 | u_int len; | 394 | u_int len; |
395 | 395 | ||
396 | debug3("%s: revoke type %s", __func__, key_type(key)); | 396 | debug3("%s: revoke type %s", __func__, key_type(key)); |
397 | if (plain_key_blob(key, &blob, &len) != 0) | 397 | if (plain_key_blob(key, &blob, &len) < 0) |
398 | return -1; | 398 | return -1; |
399 | return revoke_blob(&krl->revoked_keys, blob, len); | 399 | return revoke_blob(&krl->revoked_keys, blob, len); |
400 | } | 400 | } |
@@ -1130,7 +1130,7 @@ is_key_revoked(struct ssh_krl *krl, const Key *key) | |||
1130 | 1130 | ||
1131 | /* Next, explicit keys */ | 1131 | /* Next, explicit keys */ |
1132 | memset(&rb, 0, sizeof(rb)); | 1132 | memset(&rb, 0, sizeof(rb)); |
1133 | if (plain_key_blob(key, &rb.blob, &rb.len) != 0) | 1133 | if (plain_key_blob(key, &rb.blob, &rb.len) < 0) |
1134 | return -1; | 1134 | return -1; |
1135 | erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); | 1135 | erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); |
1136 | free(rb.blob); | 1136 | free(rb.blob); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: monitor.c,v 1.133 2014/05/03 17:20:34 markus Exp $ */ | 1 | /* $OpenBSD: monitor.c,v 1.134 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | 3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> |
4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> | 4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> |
@@ -40,9 +40,10 @@ | |||
40 | #endif | 40 | #endif |
41 | #include <pwd.h> | 41 | #include <pwd.h> |
42 | #include <signal.h> | 42 | #include <signal.h> |
43 | #include <stdarg.h> | ||
44 | #include <stdlib.h> | 43 | #include <stdlib.h> |
45 | #include <string.h> | 44 | #include <string.h> |
45 | #include <stdarg.h> | ||
46 | #include <stdio.h> | ||
46 | #include <unistd.h> | 47 | #include <unistd.h> |
47 | #ifdef HAVE_POLL_H | 48 | #ifdef HAVE_POLL_H |
48 | #include <poll.h> | 49 | #include <poll.h> |
diff --git a/openbsd-compat/openssl-compat.c b/openbsd-compat/openssl-compat.c index 0e5f2cea5..36570e4ad 100644 --- a/openbsd-compat/openssl-compat.c +++ b/openbsd-compat/openssl-compat.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $Id: openssl-compat.c,v 1.18 2014/06/17 13:06:08 dtucker Exp $ */ | 1 | /* $Id: openssl-compat.c,v 1.19 2014/07/02 05:28:07 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au> | 4 | * Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au> |
@@ -16,6 +16,7 @@ | |||
16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #define SSH_DONT_OVERLOAD_OPENSSL_FUNCS | ||
19 | #include "includes.h" | 20 | #include "includes.h" |
20 | 21 | ||
21 | #include <stdarg.h> | 22 | #include <stdarg.h> |
@@ -26,13 +27,8 @@ | |||
26 | # include <openssl/conf.h> | 27 | # include <openssl/conf.h> |
27 | #endif | 28 | #endif |
28 | 29 | ||
29 | #ifndef HAVE_RSA_GET_DEFAULT_METHOD | ||
30 | # include <openssl/rsa.h> | ||
31 | #endif | ||
32 | |||
33 | #include "log.h" | 30 | #include "log.h" |
34 | 31 | ||
35 | #define SSH_DONT_OVERLOAD_OPENSSL_FUNCS | ||
36 | #include "openssl-compat.h" | 32 | #include "openssl-compat.h" |
37 | 33 | ||
38 | /* | 34 | /* |
@@ -70,139 +66,6 @@ ssh_compatible_openssl(long headerver, long libver) | |||
70 | return 0; | 66 | return 0; |
71 | } | 67 | } |
72 | 68 | ||
73 | #ifdef SSH_OLD_EVP | ||
74 | int | ||
75 | ssh_EVP_CipherInit(EVP_CIPHER_CTX *evp, const EVP_CIPHER *type, | ||
76 | unsigned char *key, unsigned char *iv, int enc) | ||
77 | { | ||
78 | EVP_CipherInit(evp, type, key, iv, enc); | ||
79 | return 1; | ||
80 | } | ||
81 | |||
82 | int | ||
83 | ssh_EVP_Cipher(EVP_CIPHER_CTX *evp, char *dst, char *src, int len) | ||
84 | { | ||
85 | EVP_Cipher(evp, dst, src, len); | ||
86 | return 1; | ||
87 | } | ||
88 | |||
89 | int | ||
90 | ssh_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *evp) | ||
91 | { | ||
92 | EVP_CIPHER_CTX_cleanup(evp); | ||
93 | return 1; | ||
94 | } | ||
95 | #endif | ||
96 | |||
97 | #ifndef HAVE_EVP_DIGESTINIT_EX | ||
98 | int | ||
99 | EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, void *engine) | ||
100 | { | ||
101 | if (engine != NULL) | ||
102 | fatal("%s: ENGINE is not supported", __func__); | ||
103 | # ifdef OPENSSL_EVP_DIGESTUPDATE_VOID | ||
104 | EVP_DigestInit(ctx, md); | ||
105 | return 1; | ||
106 | # else | ||
107 | return EVP_DigestInit(ctx, md); | ||
108 | # endif | ||
109 | } | ||
110 | #endif | ||
111 | |||
112 | #ifndef HAVE_EVP_DIGESTFINAL_EX | ||
113 | int | ||
114 | EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s) | ||
115 | { | ||
116 | # ifdef OPENSSL_EVP_DIGESTUPDATE_VOID | ||
117 | EVP_DigestFinal(ctx, md, s); | ||
118 | return 1; | ||
119 | # else | ||
120 | return EVP_DigestFinal(ctx, md, s); | ||
121 | # endif | ||
122 | } | ||
123 | #endif | ||
124 | |||
125 | #ifdef OPENSSL_EVP_DIGESTUPDATE_VOID | ||
126 | int | ||
127 | ssh_EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt) | ||
128 | { | ||
129 | EVP_DigestUpdate(ctx, d, cnt); | ||
130 | return 1; | ||
131 | } | ||
132 | #endif | ||
133 | |||
134 | #ifndef HAVE_EVP_MD_CTX_COPY_EX | ||
135 | int | ||
136 | EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) | ||
137 | { | ||
138 | return EVP_MD_CTX_copy(out, in); | ||
139 | } | ||
140 | #endif | ||
141 | |||
142 | #ifndef HAVE_BN_IS_PRIME_EX | ||
143 | int | ||
144 | BN_is_prime_ex(const BIGNUM *p, int nchecks, BN_CTX *ctx, void *cb) | ||
145 | { | ||
146 | if (cb != NULL) | ||
147 | fatal("%s: callback args not supported", __func__); | ||
148 | return BN_is_prime(p, nchecks, NULL, ctx, NULL); | ||
149 | } | ||
150 | #endif | ||
151 | |||
152 | #ifndef HAVE_RSA_GENERATE_KEY_EX | ||
153 | int | ||
154 | RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *bn_e, void *cb) | ||
155 | { | ||
156 | RSA *new_rsa, tmp_rsa; | ||
157 | unsigned long e; | ||
158 | |||
159 | if (cb != NULL) | ||
160 | fatal("%s: callback args not supported", __func__); | ||
161 | e = BN_get_word(bn_e); | ||
162 | if (e == 0xffffffffL) | ||
163 | fatal("%s: value of e too large", __func__); | ||
164 | new_rsa = RSA_generate_key(bits, e, NULL, NULL); | ||
165 | if (new_rsa == NULL) | ||
166 | return 0; | ||
167 | /* swap rsa/new_rsa then free new_rsa */ | ||
168 | tmp_rsa = *rsa; | ||
169 | *rsa = *new_rsa; | ||
170 | *new_rsa = tmp_rsa; | ||
171 | RSA_free(new_rsa); | ||
172 | return 1; | ||
173 | } | ||
174 | #endif | ||
175 | |||
176 | #ifndef HAVE_DSA_GENERATE_PARAMETERS_EX | ||
177 | int | ||
178 | DSA_generate_parameters_ex(DSA *dsa, int bits, const unsigned char *seed, | ||
179 | int seed_len, int *counter_ret, unsigned long *h_ret, void *cb) | ||
180 | { | ||
181 | DSA *new_dsa, tmp_dsa; | ||
182 | |||
183 | if (cb != NULL) | ||
184 | fatal("%s: callback args not supported", __func__); | ||
185 | new_dsa = DSA_generate_parameters(bits, (unsigned char *)seed, seed_len, | ||
186 | counter_ret, h_ret, NULL, NULL); | ||
187 | if (new_dsa == NULL) | ||
188 | return 0; | ||
189 | /* swap dsa/new_dsa then free new_dsa */ | ||
190 | tmp_dsa = *dsa; | ||
191 | *dsa = *new_dsa; | ||
192 | *new_dsa = tmp_dsa; | ||
193 | DSA_free(new_dsa); | ||
194 | return 1; | ||
195 | } | ||
196 | #endif | ||
197 | |||
198 | #ifndef HAVE_RSA_GET_DEFAULT_METHOD | ||
199 | RSA_METHOD * | ||
200 | RSA_get_default_method(void) | ||
201 | { | ||
202 | return RSA_PKCS1_SSLeay(); | ||
203 | } | ||
204 | #endif | ||
205 | |||
206 | #ifdef USE_OPENSSL_ENGINE | 69 | #ifdef USE_OPENSSL_ENGINE |
207 | void | 70 | void |
208 | ssh_OpenSSL_add_all_algorithms(void) | 71 | ssh_OpenSSL_add_all_algorithms(void) |
diff --git a/openbsd-compat/openssl-compat.h b/openbsd-compat/openssl-compat.h index 199dcc882..d088d2962 100644 --- a/openbsd-compat/openssl-compat.h +++ b/openbsd-compat/openssl-compat.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $Id: openssl-compat.h,v 1.27 2014/06/17 13:06:08 dtucker Exp $ */ | 1 | /* $Id: openssl-compat.h,v 1.28 2014/07/02 05:28:07 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au> | 4 | * Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au> |
@@ -24,22 +24,8 @@ | |||
24 | 24 | ||
25 | int ssh_compatible_openssl(long, long); | 25 | int ssh_compatible_openssl(long, long); |
26 | 26 | ||
27 | /* Only in 0.9.8 */ | 27 | #if (OPENSSL_VERSION_NUMBER <= 0x0090805fL) |
28 | #ifndef OPENSSL_DSA_MAX_MODULUS_BITS | 28 | #error OpenSSL 0.9.8f or greater is required |
29 | # define OPENSSL_DSA_MAX_MODULUS_BITS 10000 | ||
30 | #endif | ||
31 | #ifndef OPENSSL_RSA_MAX_MODULUS_BITS | ||
32 | # define OPENSSL_RSA_MAX_MODULUS_BITS 16384 | ||
33 | #endif | ||
34 | |||
35 | /* OPENSSL_free() is Free() in versions before OpenSSL 0.9.6 */ | ||
36 | #if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x0090600f) | ||
37 | # define OPENSSL_free(x) Free(x) | ||
38 | #endif | ||
39 | |||
40 | #if OPENSSL_VERSION_NUMBER < 0x00906000L | ||
41 | # define SSH_OLD_EVP | ||
42 | # define EVP_CIPHER_CTX_get_app_data(e) ((e)->app_data) | ||
43 | #endif | 29 | #endif |
44 | 30 | ||
45 | #if OPENSSL_VERSION_NUMBER < 0x10000001L | 31 | #if OPENSSL_VERSION_NUMBER < 0x10000001L |
@@ -48,31 +34,6 @@ int ssh_compatible_openssl(long, long); | |||
48 | # define LIBCRYPTO_EVP_INL_TYPE size_t | 34 | # define LIBCRYPTO_EVP_INL_TYPE size_t |
49 | #endif | 35 | #endif |
50 | 36 | ||
51 | #if (OPENSSL_VERSION_NUMBER < 0x00907000L) || defined(OPENSSL_LOBOTOMISED_AES) | ||
52 | # define USE_BUILTIN_RIJNDAEL | ||
53 | #endif | ||
54 | |||
55 | #ifdef USE_BUILTIN_RIJNDAEL | ||
56 | # include "rijndael.h" | ||
57 | # define AES_KEY rijndael_ctx | ||
58 | # define AES_BLOCK_SIZE 16 | ||
59 | # define AES_encrypt(a, b, c) rijndael_encrypt(c, a, b) | ||
60 | # define AES_set_encrypt_key(a, b, c) rijndael_set_key(c, (char *)a, b, 1) | ||
61 | # define EVP_aes_128_cbc evp_rijndael | ||
62 | # define EVP_aes_192_cbc evp_rijndael | ||
63 | # define EVP_aes_256_cbc evp_rijndael | ||
64 | const EVP_CIPHER *evp_rijndael(void); | ||
65 | void ssh_rijndael_iv(EVP_CIPHER_CTX *, int, u_char *, u_int); | ||
66 | #endif | ||
67 | |||
68 | #ifndef OPENSSL_HAVE_EVPCTR | ||
69 | #define EVP_aes_128_ctr evp_aes_128_ctr | ||
70 | #define EVP_aes_192_ctr evp_aes_128_ctr | ||
71 | #define EVP_aes_256_ctr evp_aes_128_ctr | ||
72 | const EVP_CIPHER *evp_aes_128_ctr(void); | ||
73 | void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, size_t); | ||
74 | #endif | ||
75 | |||
76 | /* Avoid some #ifdef. Code that uses these is unreachable without GCM */ | 37 | /* Avoid some #ifdef. Code that uses these is unreachable without GCM */ |
77 | #if !defined(OPENSSL_HAVE_EVPGCM) && !defined(EVP_CTRL_GCM_SET_IV_FIXED) | 38 | #if !defined(OPENSSL_HAVE_EVPGCM) && !defined(EVP_CTRL_GCM_SET_IV_FIXED) |
78 | # define EVP_CTRL_GCM_SET_IV_FIXED -1 | 39 | # define EVP_CTRL_GCM_SET_IV_FIXED -1 |
@@ -90,26 +51,9 @@ void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, size_t); | |||
90 | # endif | 51 | # endif |
91 | #endif | 52 | #endif |
92 | 53 | ||
93 | #if OPENSSL_VERSION_NUMBER < 0x00907000L | ||
94 | #define EVP_X_STATE(evp) &(evp).c | ||
95 | #define EVP_X_STATE_LEN(evp) sizeof((evp).c) | ||
96 | #else | ||
97 | #define EVP_X_STATE(evp) (evp).cipher_data | ||
98 | #define EVP_X_STATE_LEN(evp) (evp).cipher->ctx_size | ||
99 | #endif | ||
100 | |||
101 | /* OpenSSL 0.9.8e returns cipher key len not context key len */ | ||
102 | #if (OPENSSL_VERSION_NUMBER == 0x0090805fL) | ||
103 | # define EVP_CIPHER_CTX_key_length(c) ((c)->key_len) | ||
104 | #endif | ||
105 | |||
106 | #ifndef HAVE_RSA_GET_DEFAULT_METHOD | ||
107 | RSA_METHOD *RSA_get_default_method(void); | ||
108 | #endif | ||
109 | |||
110 | /* | 54 | /* |
111 | * We overload some of the OpenSSL crypto functions with ssh_* equivalents | 55 | * We overload some of the OpenSSL crypto functions with ssh_* equivalents |
112 | * which cater for older and/or less featureful OpenSSL version. | 56 | * to automatically handle OpenSSL engine initialisation. |
113 | * | 57 | * |
114 | * In order for the compat library to call the real functions, it must | 58 | * In order for the compat library to call the real functions, it must |
115 | * define SSH_DONT_OVERLOAD_OPENSSL_FUNCS before including this file and | 59 | * define SSH_DONT_OVERLOAD_OPENSSL_FUNCS before including this file and |
@@ -117,19 +61,6 @@ RSA_METHOD *RSA_get_default_method(void); | |||
117 | */ | 61 | */ |
118 | #ifndef SSH_DONT_OVERLOAD_OPENSSL_FUNCS | 62 | #ifndef SSH_DONT_OVERLOAD_OPENSSL_FUNCS |
119 | 63 | ||
120 | # ifdef SSH_OLD_EVP | ||
121 | # ifdef EVP_Cipher | ||
122 | # undef EVP_Cipher | ||
123 | # endif | ||
124 | # define EVP_CipherInit(a,b,c,d,e) ssh_EVP_CipherInit((a),(b),(c),(d),(e)) | ||
125 | # define EVP_Cipher(a,b,c,d) ssh_EVP_Cipher((a),(b),(c),(d)) | ||
126 | # define EVP_CIPHER_CTX_cleanup(a) ssh_EVP_CIPHER_CTX_cleanup((a)) | ||
127 | # endif /* SSH_OLD_EVP */ | ||
128 | |||
129 | # ifdef OPENSSL_EVP_DIGESTUPDATE_VOID | ||
130 | # define EVP_DigestUpdate(a,b,c) ssh_EVP_DigestUpdate((a),(b),(c)) | ||
131 | # endif | ||
132 | |||
133 | # ifdef USE_OPENSSL_ENGINE | 64 | # ifdef USE_OPENSSL_ENGINE |
134 | # ifdef OpenSSL_add_all_algorithms | 65 | # ifdef OpenSSL_add_all_algorithms |
135 | # undef OpenSSL_add_all_algorithms | 66 | # undef OpenSSL_add_all_algorithms |
@@ -137,48 +68,7 @@ RSA_METHOD *RSA_get_default_method(void); | |||
137 | # define OpenSSL_add_all_algorithms() ssh_OpenSSL_add_all_algorithms() | 68 | # define OpenSSL_add_all_algorithms() ssh_OpenSSL_add_all_algorithms() |
138 | # endif | 69 | # endif |
139 | 70 | ||
140 | # ifndef HAVE_BN_IS_PRIME_EX | ||
141 | int BN_is_prime_ex(const BIGNUM *, int, BN_CTX *, void *); | ||
142 | # endif | ||
143 | |||
144 | # ifndef HAVE_DSA_GENERATE_PARAMETERS_EX | ||
145 | int DSA_generate_parameters_ex(DSA *, int, const unsigned char *, int, int *, | ||
146 | unsigned long *, void *); | ||
147 | # endif | ||
148 | |||
149 | # ifndef HAVE_RSA_GENERATE_KEY_EX | ||
150 | int RSA_generate_key_ex(RSA *, int, BIGNUM *, void *); | ||
151 | # endif | ||
152 | |||
153 | # ifndef HAVE_EVP_DIGESTINIT_EX | ||
154 | int EVP_DigestInit_ex(EVP_MD_CTX *, const EVP_MD *, void *); | ||
155 | # endif | ||
156 | |||
157 | # ifndef HAVE_EVP_DISESTFINAL_EX | ||
158 | int EVP_DigestFinal_ex(EVP_MD_CTX *, unsigned char *, unsigned int *); | ||
159 | # endif | ||
160 | |||
161 | # ifndef EVP_MD_CTX_COPY_EX | ||
162 | int EVP_MD_CTX_copy_ex(EVP_MD_CTX *, const EVP_MD_CTX *); | ||
163 | # endif | ||
164 | |||
165 | int ssh_EVP_CipherInit(EVP_CIPHER_CTX *, const EVP_CIPHER *, unsigned char *, | ||
166 | unsigned char *, int); | ||
167 | int ssh_EVP_Cipher(EVP_CIPHER_CTX *, char *, char *, int); | ||
168 | int ssh_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *); | ||
169 | void ssh_OpenSSL_add_all_algorithms(void); | 71 | void ssh_OpenSSL_add_all_algorithms(void); |
170 | 72 | ||
171 | # ifndef HAVE_HMAC_CTX_INIT | ||
172 | # define HMAC_CTX_init(a) | ||
173 | # endif | ||
174 | |||
175 | # ifndef HAVE_EVP_MD_CTX_INIT | ||
176 | # define EVP_MD_CTX_init(a) | ||
177 | # endif | ||
178 | |||
179 | # ifndef HAVE_EVP_MD_CTX_CLEANUP | ||
180 | # define EVP_MD_CTX_cleanup(a) | ||
181 | # endif | ||
182 | |||
183 | #endif /* SSH_DONT_OVERLOAD_OPENSSL_FUNCS */ | 73 | #endif /* SSH_DONT_OVERLOAD_OPENSSL_FUNCS */ |
184 | 74 | ||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: packet.c,v 1.196 2014/05/03 17:20:34 markus Exp $ */ | 1 | /* $OpenBSD: packet.c,v 1.197 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -78,6 +78,7 @@ | |||
78 | #include "canohost.h" | 78 | #include "canohost.h" |
79 | #include "misc.h" | 79 | #include "misc.h" |
80 | #include "ssh.h" | 80 | #include "ssh.h" |
81 | #include "ssherr.h" | ||
81 | #include "roaming.h" | 82 | #include "roaming.h" |
82 | 83 | ||
83 | #ifdef PACKET_DEBUG | 84 | #ifdef PACKET_DEBUG |
@@ -222,6 +223,7 @@ void | |||
222 | packet_set_connection(int fd_in, int fd_out) | 223 | packet_set_connection(int fd_in, int fd_out) |
223 | { | 224 | { |
224 | const Cipher *none = cipher_by_name("none"); | 225 | const Cipher *none = cipher_by_name("none"); |
226 | int r; | ||
225 | 227 | ||
226 | if (none == NULL) | 228 | if (none == NULL) |
227 | fatal("packet_set_connection: cannot load cipher 'none'"); | 229 | fatal("packet_set_connection: cannot load cipher 'none'"); |
@@ -229,10 +231,11 @@ packet_set_connection(int fd_in, int fd_out) | |||
229 | active_state = alloc_session_state(); | 231 | active_state = alloc_session_state(); |
230 | active_state->connection_in = fd_in; | 232 | active_state->connection_in = fd_in; |
231 | active_state->connection_out = fd_out; | 233 | active_state->connection_out = fd_out; |
232 | cipher_init(&active_state->send_context, none, (const u_char *)"", | 234 | if ((r = cipher_init(&active_state->send_context, none, |
233 | 0, NULL, 0, CIPHER_ENCRYPT); | 235 | (const u_char *)"", 0, NULL, 0, CIPHER_ENCRYPT)) != 0 || |
234 | cipher_init(&active_state->receive_context, none, (const u_char *)"", | 236 | (r = cipher_init(&active_state->receive_context, none, |
235 | 0, NULL, 0, CIPHER_DECRYPT); | 237 | (const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0) |
238 | fatal("%s: cipher_init: %s", __func__, ssh_err(r)); | ||
236 | active_state->newkeys[MODE_IN] = active_state->newkeys[MODE_OUT] = NULL; | 239 | active_state->newkeys[MODE_IN] = active_state->newkeys[MODE_OUT] = NULL; |
237 | if (!active_state->initialized) { | 240 | if (!active_state->initialized) { |
238 | active_state->initialized = 1; | 241 | active_state->initialized = 1; |
@@ -329,13 +332,15 @@ void | |||
329 | packet_get_keyiv(int mode, u_char *iv, u_int len) | 332 | packet_get_keyiv(int mode, u_char *iv, u_int len) |
330 | { | 333 | { |
331 | CipherContext *cc; | 334 | CipherContext *cc; |
335 | int r; | ||
332 | 336 | ||
333 | if (mode == MODE_OUT) | 337 | if (mode == MODE_OUT) |
334 | cc = &active_state->send_context; | 338 | cc = &active_state->send_context; |
335 | else | 339 | else |
336 | cc = &active_state->receive_context; | 340 | cc = &active_state->receive_context; |
337 | 341 | ||
338 | cipher_get_keyiv(cc, iv, len); | 342 | if ((r = cipher_get_keyiv(cc, iv, len)) != 0) |
343 | fatal("%s: cipher_get_keyiv: %s", __func__, ssh_err(r)); | ||
339 | } | 344 | } |
340 | 345 | ||
341 | int | 346 | int |
@@ -381,13 +386,15 @@ void | |||
381 | packet_set_iv(int mode, u_char *dat) | 386 | packet_set_iv(int mode, u_char *dat) |
382 | { | 387 | { |
383 | CipherContext *cc; | 388 | CipherContext *cc; |
389 | int r; | ||
384 | 390 | ||
385 | if (mode == MODE_OUT) | 391 | if (mode == MODE_OUT) |
386 | cc = &active_state->send_context; | 392 | cc = &active_state->send_context; |
387 | else | 393 | else |
388 | cc = &active_state->receive_context; | 394 | cc = &active_state->receive_context; |
389 | 395 | ||
390 | cipher_set_keyiv(cc, dat); | 396 | if ((r = cipher_set_keyiv(cc, dat)) != 0) |
397 | fatal("%s: cipher_set_keyiv: %s", __func__, ssh_err(r)); | ||
391 | } | 398 | } |
392 | 399 | ||
393 | int | 400 | int |
@@ -552,6 +559,7 @@ void | |||
552 | packet_set_encryption_key(const u_char *key, u_int keylen, int number) | 559 | packet_set_encryption_key(const u_char *key, u_int keylen, int number) |
553 | { | 560 | { |
554 | const Cipher *cipher = cipher_by_number(number); | 561 | const Cipher *cipher = cipher_by_number(number); |
562 | int r; | ||
555 | 563 | ||
556 | if (cipher == NULL) | 564 | if (cipher == NULL) |
557 | fatal("packet_set_encryption_key: unknown cipher number %d", number); | 565 | fatal("packet_set_encryption_key: unknown cipher number %d", number); |
@@ -561,10 +569,11 @@ packet_set_encryption_key(const u_char *key, u_int keylen, int number) | |||
561 | fatal("packet_set_encryption_key: keylen too big: %d", keylen); | 569 | fatal("packet_set_encryption_key: keylen too big: %d", keylen); |
562 | memcpy(active_state->ssh1_key, key, keylen); | 570 | memcpy(active_state->ssh1_key, key, keylen); |
563 | active_state->ssh1_keylen = keylen; | 571 | active_state->ssh1_keylen = keylen; |
564 | cipher_init(&active_state->send_context, cipher, key, keylen, NULL, | 572 | if ((r = cipher_init(&active_state->send_context, cipher, |
565 | 0, CIPHER_ENCRYPT); | 573 | key, keylen, NULL, 0, CIPHER_ENCRYPT)) != 0 || |
566 | cipher_init(&active_state->receive_context, cipher, key, keylen, NULL, | 574 | (r = cipher_init(&active_state->receive_context, cipher, |
567 | 0, CIPHER_DECRYPT); | 575 | key, keylen, NULL, 0, CIPHER_DECRYPT)) != 0) |
576 | fatal("%s: cipher_init: %s", __func__, ssh_err(r)); | ||
568 | } | 577 | } |
569 | 578 | ||
570 | u_int | 579 | u_int |
@@ -744,7 +753,7 @@ set_newkeys(int mode) | |||
744 | Comp *comp; | 753 | Comp *comp; |
745 | CipherContext *cc; | 754 | CipherContext *cc; |
746 | u_int64_t *max_blocks; | 755 | u_int64_t *max_blocks; |
747 | int crypt_type; | 756 | int r, crypt_type; |
748 | 757 | ||
749 | debug2("set_newkeys: mode %d", mode); | 758 | debug2("set_newkeys: mode %d", mode); |
750 | 759 | ||
@@ -786,8 +795,9 @@ set_newkeys(int mode) | |||
786 | if (cipher_authlen(enc->cipher) == 0 && mac_init(mac) == 0) | 795 | if (cipher_authlen(enc->cipher) == 0 && mac_init(mac) == 0) |
787 | mac->enabled = 1; | 796 | mac->enabled = 1; |
788 | DBG(debug("cipher_init_context: %d", mode)); | 797 | DBG(debug("cipher_init_context: %d", mode)); |
789 | cipher_init(cc, enc->cipher, enc->key, enc->key_len, | 798 | if ((r = cipher_init(cc, enc->cipher, enc->key, enc->key_len, |
790 | enc->iv, enc->iv_len, crypt_type); | 799 | enc->iv, enc->iv_len, crypt_type)) != 0) |
800 | fatal("%s: cipher_init: %s", __func__, ssh_err(r)); | ||
791 | /* Deleting the keys does not gain extra security */ | 801 | /* Deleting the keys does not gain extra security */ |
792 | /* explicit_bzero(enc->iv, enc->block_size); | 802 | /* explicit_bzero(enc->iv, enc->block_size); |
793 | explicit_bzero(enc->key, enc->key_len); | 803 | explicit_bzero(enc->key, enc->key_len); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: rsa.c,v 1.31 2014/02/02 03:44:31 djm Exp $ */ | 1 | /* $OpenBSD: rsa.c,v 1.32 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -67,85 +67,122 @@ | |||
67 | #include <stdarg.h> | 67 | #include <stdarg.h> |
68 | #include <string.h> | 68 | #include <string.h> |
69 | 69 | ||
70 | #include "xmalloc.h" | ||
71 | #include "rsa.h" | 70 | #include "rsa.h" |
72 | #include "log.h" | 71 | #include "log.h" |
72 | #include "ssherr.h" | ||
73 | 73 | ||
74 | void | 74 | int |
75 | rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key) | 75 | rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key) |
76 | { | 76 | { |
77 | u_char *inbuf, *outbuf; | 77 | u_char *inbuf = NULL, *outbuf = NULL; |
78 | int len, ilen, olen; | 78 | int len, ilen, olen, r = SSH_ERR_INTERNAL_ERROR; |
79 | 79 | ||
80 | if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e)) | 80 | if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e)) |
81 | fatal("rsa_public_encrypt() exponent too small or not odd"); | 81 | return SSH_ERR_INVALID_ARGUMENT; |
82 | 82 | ||
83 | olen = BN_num_bytes(key->n); | 83 | olen = BN_num_bytes(key->n); |
84 | outbuf = xmalloc(olen); | 84 | if ((outbuf = malloc(olen)) == NULL) { |
85 | r = SSH_ERR_ALLOC_FAIL; | ||
86 | goto out; | ||
87 | } | ||
85 | 88 | ||
86 | ilen = BN_num_bytes(in); | 89 | ilen = BN_num_bytes(in); |
87 | inbuf = xmalloc(ilen); | 90 | if ((inbuf = malloc(ilen)) == NULL) { |
91 | r = SSH_ERR_ALLOC_FAIL; | ||
92 | goto out; | ||
93 | } | ||
88 | BN_bn2bin(in, inbuf); | 94 | BN_bn2bin(in, inbuf); |
89 | 95 | ||
90 | if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key, | 96 | if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key, |
91 | RSA_PKCS1_PADDING)) <= 0) | 97 | RSA_PKCS1_PADDING)) <= 0) { |
92 | fatal("rsa_public_encrypt() failed"); | 98 | r = SSH_ERR_LIBCRYPTO_ERROR; |
99 | goto out; | ||
100 | } | ||
93 | 101 | ||
94 | if (BN_bin2bn(outbuf, len, out) == NULL) | 102 | if (BN_bin2bn(outbuf, len, out) == NULL) { |
95 | fatal("rsa_public_encrypt: BN_bin2bn failed"); | 103 | r = SSH_ERR_LIBCRYPTO_ERROR; |
104 | goto out; | ||
105 | } | ||
106 | r = 0; | ||
96 | 107 | ||
97 | explicit_bzero(outbuf, olen); | 108 | out: |
98 | explicit_bzero(inbuf, ilen); | 109 | if (outbuf != NULL) { |
99 | free(outbuf); | 110 | explicit_bzero(outbuf, olen); |
100 | free(inbuf); | 111 | free(outbuf); |
112 | } | ||
113 | if (inbuf != NULL) { | ||
114 | explicit_bzero(inbuf, ilen); | ||
115 | free(inbuf); | ||
116 | } | ||
117 | return r; | ||
101 | } | 118 | } |
102 | 119 | ||
103 | int | 120 | int |
104 | rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key) | 121 | rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key) |
105 | { | 122 | { |
106 | u_char *inbuf, *outbuf; | 123 | u_char *inbuf = NULL, *outbuf = NULL; |
107 | int len, ilen, olen; | 124 | int len, ilen, olen, r = SSH_ERR_INTERNAL_ERROR; |
108 | 125 | ||
109 | olen = BN_num_bytes(key->n); | 126 | olen = BN_num_bytes(key->n); |
110 | outbuf = xmalloc(olen); | 127 | if ((outbuf = malloc(olen)) == NULL) { |
128 | r = SSH_ERR_ALLOC_FAIL; | ||
129 | goto out; | ||
130 | } | ||
111 | 131 | ||
112 | ilen = BN_num_bytes(in); | 132 | ilen = BN_num_bytes(in); |
113 | inbuf = xmalloc(ilen); | 133 | if ((inbuf = malloc(ilen)) == NULL) { |
134 | r = SSH_ERR_ALLOC_FAIL; | ||
135 | goto out; | ||
136 | } | ||
114 | BN_bn2bin(in, inbuf); | 137 | BN_bn2bin(in, inbuf); |
115 | 138 | ||
116 | if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key, | 139 | if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key, |
117 | RSA_PKCS1_PADDING)) <= 0) { | 140 | RSA_PKCS1_PADDING)) <= 0) { |
118 | error("rsa_private_decrypt() failed"); | 141 | r = SSH_ERR_LIBCRYPTO_ERROR; |
119 | } else { | 142 | goto out; |
120 | if (BN_bin2bn(outbuf, len, out) == NULL) | 143 | } else if (BN_bin2bn(outbuf, len, out) == NULL) { |
121 | fatal("rsa_private_decrypt: BN_bin2bn failed"); | 144 | r = SSH_ERR_LIBCRYPTO_ERROR; |
145 | goto out; | ||
146 | } | ||
147 | r = 0; | ||
148 | out: | ||
149 | if (outbuf != NULL) { | ||
150 | explicit_bzero(outbuf, olen); | ||
151 | free(outbuf); | ||
152 | } | ||
153 | if (inbuf != NULL) { | ||
154 | explicit_bzero(inbuf, ilen); | ||
155 | free(inbuf); | ||
122 | } | 156 | } |
123 | explicit_bzero(outbuf, olen); | 157 | return r; |
124 | explicit_bzero(inbuf, ilen); | ||
125 | free(outbuf); | ||
126 | free(inbuf); | ||
127 | return len; | ||
128 | } | 158 | } |
129 | 159 | ||
130 | /* calculate p-1 and q-1 */ | 160 | /* calculate p-1 and q-1 */ |
131 | void | 161 | int |
132 | rsa_generate_additional_parameters(RSA *rsa) | 162 | rsa_generate_additional_parameters(RSA *rsa) |
133 | { | 163 | { |
134 | BIGNUM *aux; | 164 | BIGNUM *aux = NULL; |
135 | BN_CTX *ctx; | 165 | BN_CTX *ctx = NULL; |
166 | int r; | ||
136 | 167 | ||
137 | if ((aux = BN_new()) == NULL) | ||
138 | fatal("rsa_generate_additional_parameters: BN_new failed"); | ||
139 | if ((ctx = BN_CTX_new()) == NULL) | 168 | if ((ctx = BN_CTX_new()) == NULL) |
140 | fatal("rsa_generate_additional_parameters: BN_CTX_new failed"); | 169 | return SSH_ERR_ALLOC_FAIL; |
170 | if ((aux = BN_new()) == NULL) { | ||
171 | r = SSH_ERR_ALLOC_FAIL; | ||
172 | goto out; | ||
173 | } | ||
141 | 174 | ||
142 | if ((BN_sub(aux, rsa->q, BN_value_one()) == 0) || | 175 | if ((BN_sub(aux, rsa->q, BN_value_one()) == 0) || |
143 | (BN_mod(rsa->dmq1, rsa->d, aux, ctx) == 0) || | 176 | (BN_mod(rsa->dmq1, rsa->d, aux, ctx) == 0) || |
144 | (BN_sub(aux, rsa->p, BN_value_one()) == 0) || | 177 | (BN_sub(aux, rsa->p, BN_value_one()) == 0) || |
145 | (BN_mod(rsa->dmp1, rsa->d, aux, ctx) == 0)) | 178 | (BN_mod(rsa->dmp1, rsa->d, aux, ctx) == 0)) { |
146 | fatal("rsa_generate_additional_parameters: BN_sub/mod failed"); | 179 | r = SSH_ERR_LIBCRYPTO_ERROR; |
147 | 180 | goto out; | |
181 | } | ||
182 | r = 0; | ||
183 | out: | ||
148 | BN_clear_free(aux); | 184 | BN_clear_free(aux); |
149 | BN_CTX_free(ctx); | 185 | BN_CTX_free(ctx); |
186 | return r; | ||
150 | } | 187 | } |
151 | 188 | ||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: rsa.h,v 1.16 2006/03/25 22:22:43 djm Exp $ */ | 1 | /* $OpenBSD: rsa.h,v 1.17 2014/06/24 01:13:21 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -19,8 +19,8 @@ | |||
19 | #include <openssl/bn.h> | 19 | #include <openssl/bn.h> |
20 | #include <openssl/rsa.h> | 20 | #include <openssl/rsa.h> |
21 | 21 | ||
22 | void rsa_public_encrypt(BIGNUM *, BIGNUM *, RSA *); | 22 | int rsa_public_encrypt(BIGNUM *, BIGNUM *, RSA *); |
23 | int rsa_private_decrypt(BIGNUM *, BIGNUM *, RSA *); | 23 | int rsa_private_decrypt(BIGNUM *, BIGNUM *, RSA *); |
24 | void rsa_generate_additional_parameters(RSA *); | 24 | int rsa_generate_additional_parameters(RSA *); |
25 | 25 | ||
26 | #endif /* RSA_H */ | 26 | #endif /* RSA_H */ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-add.c,v 1.109 2014/02/02 03:44:31 djm Exp $ */ | 1 | /* $OpenBSD: ssh-add.c,v 1.110 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -62,6 +62,7 @@ | |||
62 | #include "authfile.h" | 62 | #include "authfile.h" |
63 | #include "pathnames.h" | 63 | #include "pathnames.h" |
64 | #include "misc.h" | 64 | #include "misc.h" |
65 | #include "ssherr.h" | ||
65 | 66 | ||
66 | /* argv0 */ | 67 | /* argv0 */ |
67 | extern char *__progname; | 68 | extern char *__progname; |
@@ -170,7 +171,7 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only) | |||
170 | Key *private, *cert; | 171 | Key *private, *cert; |
171 | char *comment = NULL; | 172 | char *comment = NULL; |
172 | char msg[1024], *certpath = NULL; | 173 | char msg[1024], *certpath = NULL; |
173 | int fd, perms_ok, ret = -1; | 174 | int r, fd, perms_ok, ret = -1; |
174 | Buffer keyblob; | 175 | Buffer keyblob; |
175 | 176 | ||
176 | if (strcmp(filename, "-") == 0) { | 177 | if (strcmp(filename, "-") == 0) { |
@@ -201,12 +202,18 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only) | |||
201 | close(fd); | 202 | close(fd); |
202 | 203 | ||
203 | /* At first, try empty passphrase */ | 204 | /* At first, try empty passphrase */ |
204 | private = key_parse_private(&keyblob, filename, "", &comment); | 205 | if ((r = sshkey_parse_private_fileblob(&keyblob, filename, "", |
206 | &private, &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) | ||
207 | fatal("Cannot parse %s: %s", filename, ssh_err(r)); | ||
205 | if (comment == NULL) | 208 | if (comment == NULL) |
206 | comment = xstrdup(filename); | 209 | comment = xstrdup(filename); |
207 | /* try last */ | 210 | /* try last */ |
208 | if (private == NULL && pass != NULL) | 211 | if (private == NULL && pass != NULL) { |
209 | private = key_parse_private(&keyblob, filename, pass, NULL); | 212 | if ((r = sshkey_parse_private_fileblob(&keyblob, filename, pass, |
213 | &private, &comment)) != 0 && | ||
214 | r != SSH_ERR_KEY_WRONG_PASSPHRASE) | ||
215 | fatal("Cannot parse %s: %s", filename, ssh_err(r)); | ||
216 | } | ||
210 | if (private == NULL) { | 217 | if (private == NULL) { |
211 | /* clear passphrase since it did not work */ | 218 | /* clear passphrase since it did not work */ |
212 | clear_pass(); | 219 | clear_pass(); |
@@ -220,8 +227,11 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only) | |||
220 | buffer_free(&keyblob); | 227 | buffer_free(&keyblob); |
221 | return -1; | 228 | return -1; |
222 | } | 229 | } |
223 | private = key_parse_private(&keyblob, filename, pass, | 230 | if ((r = sshkey_parse_private_fileblob(&keyblob, |
224 | &comment); | 231 | filename, pass, &private, &comment)) != 0 && |
232 | r != SSH_ERR_KEY_WRONG_PASSPHRASE) | ||
233 | fatal("Cannot parse %s: %s", | ||
234 | filename, ssh_err(r)); | ||
225 | if (private != NULL) | 235 | if (private != NULL) |
226 | break; | 236 | break; |
227 | clear_pass(); | 237 | clear_pass(); |
diff --git a/ssh-agent.c b/ssh-agent.c index bc96ad705..693d763e2 100644 --- a/ssh-agent.c +++ b/ssh-agent.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-agent.c,v 1.185 2014/04/29 18:01:49 markus Exp $ */ | 1 | /* $OpenBSD: ssh-agent.c,v 1.186 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -278,7 +278,7 @@ process_authentication_challenge1(SocketEntry *e) | |||
278 | if (id != NULL && (!id->confirm || confirm_key(id) == 0)) { | 278 | if (id != NULL && (!id->confirm || confirm_key(id) == 0)) { |
279 | Key *private = id->key; | 279 | Key *private = id->key; |
280 | /* Decrypt the challenge using the private key. */ | 280 | /* Decrypt the challenge using the private key. */ |
281 | if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0) | 281 | if (rsa_private_decrypt(challenge, challenge, private->rsa) != 0) |
282 | goto failure; | 282 | goto failure; |
283 | 283 | ||
284 | /* The response is MD5 of decrypted challenge plus session id. */ | 284 | /* The response is MD5 of decrypted challenge plus session id. */ |
@@ -365,12 +365,16 @@ process_sign_request2(SocketEntry *e) | |||
365 | static void | 365 | static void |
366 | process_remove_identity(SocketEntry *e, int version) | 366 | process_remove_identity(SocketEntry *e, int version) |
367 | { | 367 | { |
368 | u_int blen, bits; | 368 | u_int blen; |
369 | int success = 0; | 369 | int success = 0; |
370 | Key *key = NULL; | 370 | Key *key = NULL; |
371 | u_char *blob; | 371 | u_char *blob; |
372 | #ifdef WITH_SSH1 | ||
373 | u_int bits; | ||
374 | #endif /* WITH_SSH1 */ | ||
372 | 375 | ||
373 | switch (version) { | 376 | switch (version) { |
377 | #ifdef WITH_SSH1 | ||
374 | case 1: | 378 | case 1: |
375 | key = key_new(KEY_RSA1); | 379 | key = key_new(KEY_RSA1); |
376 | bits = buffer_get_int(&e->request); | 380 | bits = buffer_get_int(&e->request); |
@@ -381,6 +385,7 @@ process_remove_identity(SocketEntry *e, int version) | |||
381 | logit("Warning: identity keysize mismatch: actual %u, announced %u", | 385 | logit("Warning: identity keysize mismatch: actual %u, announced %u", |
382 | key_size(key), bits); | 386 | key_size(key), bits); |
383 | break; | 387 | break; |
388 | #endif /* WITH_SSH1 */ | ||
384 | case 2: | 389 | case 2: |
385 | blob = buffer_get_string(&e->request, &blen); | 390 | blob = buffer_get_string(&e->request, &blen); |
386 | key = key_from_blob(blob, blen); | 391 | key = key_from_blob(blob, blen); |
@@ -477,6 +482,7 @@ process_add_identity(SocketEntry *e, int version) | |||
477 | Key *k = NULL; | 482 | Key *k = NULL; |
478 | 483 | ||
479 | switch (version) { | 484 | switch (version) { |
485 | #ifdef WITH_SSH1 | ||
480 | case 1: | 486 | case 1: |
481 | k = key_new_private(KEY_RSA1); | 487 | k = key_new_private(KEY_RSA1); |
482 | (void) buffer_get_int(&e->request); /* ignored */ | 488 | (void) buffer_get_int(&e->request); /* ignored */ |
@@ -490,7 +496,9 @@ process_add_identity(SocketEntry *e, int version) | |||
490 | buffer_get_bignum(&e->request, k->rsa->p); /* q */ | 496 | buffer_get_bignum(&e->request, k->rsa->p); /* q */ |
491 | 497 | ||
492 | /* Generate additional parameters */ | 498 | /* Generate additional parameters */ |
493 | rsa_generate_additional_parameters(k->rsa); | 499 | if (rsa_generate_additional_parameters(k->rsa) != 0) |
500 | fatal("%s: rsa_generate_additional_parameters " | ||
501 | "error", __func__); | ||
494 | 502 | ||
495 | /* enable blinding */ | 503 | /* enable blinding */ |
496 | if (RSA_blinding_on(k->rsa, NULL) != 1) { | 504 | if (RSA_blinding_on(k->rsa, NULL) != 1) { |
@@ -499,6 +507,7 @@ process_add_identity(SocketEntry *e, int version) | |||
499 | goto send; | 507 | goto send; |
500 | } | 508 | } |
501 | break; | 509 | break; |
510 | #endif /* WITH_SSH1 */ | ||
502 | case 2: | 511 | case 2: |
503 | k = key_private_deserialize(&e->request); | 512 | k = key_private_deserialize(&e->request); |
504 | if (k == NULL) { | 513 | if (k == NULL) { |
@@ -507,11 +516,10 @@ process_add_identity(SocketEntry *e, int version) | |||
507 | } | 516 | } |
508 | break; | 517 | break; |
509 | } | 518 | } |
510 | comment = buffer_get_string(&e->request, NULL); | 519 | if (k == NULL) |
511 | if (k == NULL) { | ||
512 | free(comment); | ||
513 | goto send; | 520 | goto send; |
514 | } | 521 | comment = buffer_get_string(&e->request, NULL); |
522 | |||
515 | while (buffer_len(&e->request)) { | 523 | while (buffer_len(&e->request)) { |
516 | switch ((type = buffer_get_char(&e->request))) { | 524 | switch ((type = buffer_get_char(&e->request))) { |
517 | case SSH_AGENT_CONSTRAIN_LIFETIME: | 525 | case SSH_AGENT_CONSTRAIN_LIFETIME: |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-dss.c,v 1.31 2014/02/02 03:44:31 djm Exp $ */ | 1 | /* $OpenBSD: ssh-dss.c,v 1.32 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -33,157 +33,186 @@ | |||
33 | #include <stdarg.h> | 33 | #include <stdarg.h> |
34 | #include <string.h> | 34 | #include <string.h> |
35 | 35 | ||
36 | #include "xmalloc.h" | 36 | #include "sshbuf.h" |
37 | #include "buffer.h" | ||
38 | #include "compat.h" | 37 | #include "compat.h" |
39 | #include "log.h" | 38 | #include "ssherr.h" |
40 | #include "key.h" | ||
41 | #include "digest.h" | 39 | #include "digest.h" |
40 | #define SSHKEY_INTERNAL | ||
41 | #include "sshkey.h" | ||
42 | 42 | ||
43 | #define INTBLOB_LEN 20 | 43 | #define INTBLOB_LEN 20 |
44 | #define SIGBLOB_LEN (2*INTBLOB_LEN) | 44 | #define SIGBLOB_LEN (2*INTBLOB_LEN) |
45 | 45 | ||
46 | int | 46 | int |
47 | ssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp, | 47 | ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
48 | const u_char *data, u_int datalen) | 48 | const u_char *data, size_t datalen, u_int compat) |
49 | { | 49 | { |
50 | DSA_SIG *sig; | 50 | DSA_SIG *sig = NULL; |
51 | u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; | 51 | u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; |
52 | u_int rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); | 52 | size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); |
53 | Buffer b; | 53 | struct sshbuf *b = NULL; |
54 | 54 | int ret = SSH_ERR_INVALID_ARGUMENT; | |
55 | if (key == NULL || key_type_plain(key->type) != KEY_DSA || | 55 | |
56 | key->dsa == NULL) { | 56 | if (lenp != NULL) |
57 | error("%s: no DSA key", __func__); | 57 | *lenp = 0; |
58 | return -1; | 58 | if (sigp != NULL) |
59 | } | 59 | *sigp = NULL; |
60 | 60 | ||
61 | if (ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, | 61 | if (key == NULL || key->dsa == NULL || |
62 | digest, sizeof(digest)) != 0) { | 62 | sshkey_type_plain(key->type) != KEY_DSA) |
63 | error("%s: ssh_digest_memory failed", __func__); | 63 | return SSH_ERR_INVALID_ARGUMENT; |
64 | return -1; | 64 | if (dlen == 0) |
65 | } | 65 | return SSH_ERR_INTERNAL_ERROR; |
66 | 66 | ||
67 | sig = DSA_do_sign(digest, dlen, key->dsa); | 67 | if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, |
68 | explicit_bzero(digest, sizeof(digest)); | 68 | digest, sizeof(digest))) != 0) |
69 | 69 | goto out; | |
70 | if (sig == NULL) { | 70 | |
71 | error("ssh_dss_sign: sign failed"); | 71 | if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { |
72 | return -1; | 72 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
73 | goto out; | ||
73 | } | 74 | } |
74 | 75 | ||
75 | rlen = BN_num_bytes(sig->r); | 76 | rlen = BN_num_bytes(sig->r); |
76 | slen = BN_num_bytes(sig->s); | 77 | slen = BN_num_bytes(sig->s); |
77 | if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { | 78 | if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { |
78 | error("bad sig size %u %u", rlen, slen); | 79 | ret = SSH_ERR_INTERNAL_ERROR; |
79 | DSA_SIG_free(sig); | 80 | goto out; |
80 | return -1; | ||
81 | } | 81 | } |
82 | explicit_bzero(sigblob, SIGBLOB_LEN); | 82 | explicit_bzero(sigblob, SIGBLOB_LEN); |
83 | BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen); | 83 | BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); |
84 | BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen); | 84 | BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen); |
85 | DSA_SIG_free(sig); | ||
86 | 85 | ||
87 | if (datafellows & SSH_BUG_SIGBLOB) { | 86 | if (compat & SSH_BUG_SIGBLOB) { |
88 | if (lenp != NULL) | ||
89 | *lenp = SIGBLOB_LEN; | ||
90 | if (sigp != NULL) { | 87 | if (sigp != NULL) { |
91 | *sigp = xmalloc(SIGBLOB_LEN); | 88 | if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) { |
89 | ret = SSH_ERR_ALLOC_FAIL; | ||
90 | goto out; | ||
91 | } | ||
92 | memcpy(*sigp, sigblob, SIGBLOB_LEN); | 92 | memcpy(*sigp, sigblob, SIGBLOB_LEN); |
93 | } | 93 | } |
94 | if (lenp != NULL) | ||
95 | *lenp = SIGBLOB_LEN; | ||
96 | ret = 0; | ||
94 | } else { | 97 | } else { |
95 | /* ietf-drafts */ | 98 | /* ietf-drafts */ |
96 | buffer_init(&b); | 99 | if ((b = sshbuf_new()) == NULL) { |
97 | buffer_put_cstring(&b, "ssh-dss"); | 100 | ret = SSH_ERR_ALLOC_FAIL; |
98 | buffer_put_string(&b, sigblob, SIGBLOB_LEN); | 101 | goto out; |
99 | len = buffer_len(&b); | 102 | } |
100 | if (lenp != NULL) | 103 | if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 || |
101 | *lenp = len; | 104 | (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0) |
105 | goto out; | ||
106 | len = sshbuf_len(b); | ||
102 | if (sigp != NULL) { | 107 | if (sigp != NULL) { |
103 | *sigp = xmalloc(len); | 108 | if ((*sigp = malloc(len)) == NULL) { |
104 | memcpy(*sigp, buffer_ptr(&b), len); | 109 | ret = SSH_ERR_ALLOC_FAIL; |
110 | goto out; | ||
111 | } | ||
112 | memcpy(*sigp, sshbuf_ptr(b), len); | ||
105 | } | 113 | } |
106 | buffer_free(&b); | 114 | if (lenp != NULL) |
115 | *lenp = len; | ||
116 | ret = 0; | ||
107 | } | 117 | } |
108 | return 0; | 118 | out: |
119 | explicit_bzero(digest, sizeof(digest)); | ||
120 | if (sig != NULL) | ||
121 | DSA_SIG_free(sig); | ||
122 | if (b != NULL) | ||
123 | sshbuf_free(b); | ||
124 | return ret; | ||
109 | } | 125 | } |
126 | |||
110 | int | 127 | int |
111 | ssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen, | 128 | ssh_dss_verify(const struct sshkey *key, |
112 | const u_char *data, u_int datalen) | 129 | const u_char *signature, size_t signaturelen, |
130 | const u_char *data, size_t datalen, u_int compat) | ||
113 | { | 131 | { |
114 | DSA_SIG *sig; | 132 | DSA_SIG *sig = NULL; |
115 | u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; | 133 | u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; |
116 | u_int len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); | 134 | size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); |
117 | int rlen, ret; | 135 | int ret = SSH_ERR_INTERNAL_ERROR; |
118 | Buffer b; | 136 | struct sshbuf *b = NULL; |
119 | 137 | char *ktype = NULL; | |
120 | if (key == NULL || key_type_plain(key->type) != KEY_DSA || | 138 | |
121 | key->dsa == NULL) { | 139 | if (key == NULL || key->dsa == NULL || |
122 | error("%s: no DSA key", __func__); | 140 | sshkey_type_plain(key->type) != KEY_DSA) |
123 | return -1; | 141 | return SSH_ERR_INVALID_ARGUMENT; |
124 | } | 142 | if (dlen == 0) |
143 | return SSH_ERR_INTERNAL_ERROR; | ||
125 | 144 | ||
126 | /* fetch signature */ | 145 | /* fetch signature */ |
127 | if (datafellows & SSH_BUG_SIGBLOB) { | 146 | if (compat & SSH_BUG_SIGBLOB) { |
128 | sigblob = xmalloc(signaturelen); | 147 | if ((sigblob = malloc(signaturelen)) == NULL) |
148 | return SSH_ERR_ALLOC_FAIL; | ||
129 | memcpy(sigblob, signature, signaturelen); | 149 | memcpy(sigblob, signature, signaturelen); |
130 | len = signaturelen; | 150 | len = signaturelen; |
131 | } else { | 151 | } else { |
132 | /* ietf-drafts */ | 152 | /* ietf-drafts */ |
133 | char *ktype; | 153 | if ((b = sshbuf_from(signature, signaturelen)) == NULL) |
134 | buffer_init(&b); | 154 | return SSH_ERR_ALLOC_FAIL; |
135 | buffer_append(&b, signature, signaturelen); | 155 | if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || |
136 | ktype = buffer_get_cstring(&b, NULL); | 156 | sshbuf_get_string(b, &sigblob, &len) != 0) { |
157 | ret = SSH_ERR_INVALID_FORMAT; | ||
158 | goto out; | ||
159 | } | ||
137 | if (strcmp("ssh-dss", ktype) != 0) { | 160 | if (strcmp("ssh-dss", ktype) != 0) { |
138 | error("%s: cannot handle type %s", __func__, ktype); | 161 | ret = SSH_ERR_KEY_TYPE_MISMATCH; |
139 | buffer_free(&b); | 162 | goto out; |
140 | free(ktype); | ||
141 | return -1; | ||
142 | } | 163 | } |
143 | free(ktype); | 164 | if (sshbuf_len(b) != 0) { |
144 | sigblob = buffer_get_string(&b, &len); | 165 | ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; |
145 | rlen = buffer_len(&b); | 166 | goto out; |
146 | buffer_free(&b); | ||
147 | if (rlen != 0) { | ||
148 | error("%s: remaining bytes in signature %d", | ||
149 | __func__, rlen); | ||
150 | free(sigblob); | ||
151 | return -1; | ||
152 | } | 167 | } |
153 | } | 168 | } |
154 | 169 | ||
155 | if (len != SIGBLOB_LEN) { | 170 | if (len != SIGBLOB_LEN) { |
156 | fatal("bad sigbloblen %u != SIGBLOB_LEN", len); | 171 | ret = SSH_ERR_INVALID_FORMAT; |
172 | goto out; | ||
157 | } | 173 | } |
158 | 174 | ||
159 | /* parse signature */ | 175 | /* parse signature */ |
160 | if ((sig = DSA_SIG_new()) == NULL) | 176 | if ((sig = DSA_SIG_new()) == NULL || |
161 | fatal("%s: DSA_SIG_new failed", __func__); | 177 | (sig->r = BN_new()) == NULL || |
162 | if ((sig->r = BN_new()) == NULL) | 178 | (sig->s = BN_new()) == NULL) { |
163 | fatal("%s: BN_new failed", __func__); | 179 | ret = SSH_ERR_ALLOC_FAIL; |
164 | if ((sig->s = BN_new()) == NULL) | 180 | goto out; |
165 | fatal("ssh_dss_verify: BN_new failed"); | 181 | } |
166 | if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) || | 182 | if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) || |
167 | (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) | 183 | (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) { |
168 | fatal("%s: BN_bin2bn failed", __func__); | 184 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
169 | 185 | goto out; | |
170 | /* clean up */ | 186 | } |
171 | explicit_bzero(sigblob, len); | ||
172 | free(sigblob); | ||
173 | 187 | ||
174 | /* sha1 the data */ | 188 | /* sha1 the data */ |
175 | if (ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, | 189 | if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, |
176 | digest, sizeof(digest)) != 0) { | 190 | digest, sizeof(digest))) != 0) |
177 | error("%s: digest_memory failed", __func__); | 191 | goto out; |
178 | return -1; | 192 | |
193 | switch (DSA_do_verify(digest, dlen, sig, key->dsa)) { | ||
194 | case 1: | ||
195 | ret = 0; | ||
196 | break; | ||
197 | case 0: | ||
198 | ret = SSH_ERR_SIGNATURE_INVALID; | ||
199 | goto out; | ||
200 | default: | ||
201 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
202 | goto out; | ||
179 | } | 203 | } |
180 | 204 | ||
181 | ret = DSA_do_verify(digest, dlen, sig, key->dsa); | 205 | out: |
182 | explicit_bzero(digest, sizeof(digest)); | 206 | explicit_bzero(digest, sizeof(digest)); |
183 | 207 | if (sig != NULL) | |
184 | DSA_SIG_free(sig); | 208 | DSA_SIG_free(sig); |
185 | 209 | if (b != NULL) | |
186 | debug("%s: signature %s", __func__, | 210 | sshbuf_free(b); |
187 | ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); | 211 | if (ktype != NULL) |
212 | free(ktype); | ||
213 | if (sigblob != NULL) { | ||
214 | explicit_bzero(sigblob, len); | ||
215 | free(sigblob); | ||
216 | } | ||
188 | return ret; | 217 | return ret; |
189 | } | 218 | } |
diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index 551c9c460..1119db045 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-ecdsa.c,v 1.10 2014/02/03 23:28:00 djm Exp $ */ | 1 | /* $OpenBSD: ssh-ecdsa.c,v 1.11 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2010 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2010 Damien Miller. All rights reserved. |
@@ -37,141 +37,155 @@ | |||
37 | 37 | ||
38 | #include <string.h> | 38 | #include <string.h> |
39 | 39 | ||
40 | #include "xmalloc.h" | 40 | #include "sshbuf.h" |
41 | #include "buffer.h" | 41 | #include "ssherr.h" |
42 | #include "compat.h" | ||
43 | #include "log.h" | ||
44 | #include "key.h" | ||
45 | #include "digest.h" | 42 | #include "digest.h" |
43 | #define SSHKEY_INTERNAL | ||
44 | #include "sshkey.h" | ||
46 | 45 | ||
46 | /* ARGSUSED */ | ||
47 | int | 47 | int |
48 | ssh_ecdsa_sign(const Key *key, u_char **sigp, u_int *lenp, | 48 | ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
49 | const u_char *data, u_int datalen) | 49 | const u_char *data, size_t datalen, u_int compat) |
50 | { | 50 | { |
51 | ECDSA_SIG *sig; | 51 | ECDSA_SIG *sig = NULL; |
52 | int hash_alg; | 52 | int hash_alg; |
53 | u_char digest[SSH_DIGEST_MAX_LENGTH]; | 53 | u_char digest[SSH_DIGEST_MAX_LENGTH]; |
54 | u_int len, dlen; | 54 | size_t len, dlen; |
55 | Buffer b, bb; | 55 | struct sshbuf *b = NULL, *bb = NULL; |
56 | int ret = SSH_ERR_INTERNAL_ERROR; | ||
56 | 57 | ||
57 | if (key == NULL || key_type_plain(key->type) != KEY_ECDSA || | 58 | if (lenp != NULL) |
58 | key->ecdsa == NULL) { | 59 | *lenp = 0; |
59 | error("%s: no ECDSA key", __func__); | 60 | if (sigp != NULL) |
60 | return -1; | 61 | *sigp = NULL; |
62 | |||
63 | if (key == NULL || key->ecdsa == NULL || | ||
64 | sshkey_type_plain(key->type) != KEY_ECDSA) | ||
65 | return SSH_ERR_INVALID_ARGUMENT; | ||
66 | |||
67 | if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || | ||
68 | (dlen = ssh_digest_bytes(hash_alg)) == 0) | ||
69 | return SSH_ERR_INTERNAL_ERROR; | ||
70 | if ((ret = ssh_digest_memory(hash_alg, data, datalen, | ||
71 | digest, sizeof(digest))) != 0) | ||
72 | goto out; | ||
73 | |||
74 | if ((sig = ECDSA_do_sign(digest, dlen, key->ecdsa)) == NULL) { | ||
75 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
76 | goto out; | ||
61 | } | 77 | } |
62 | 78 | ||
63 | hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid); | 79 | if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) { |
64 | if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { | 80 | ret = SSH_ERR_ALLOC_FAIL; |
65 | error("%s: bad hash algorithm %d", __func__, hash_alg); | 81 | goto out; |
66 | return -1; | ||
67 | } | ||
68 | if (ssh_digest_memory(hash_alg, data, datalen, | ||
69 | digest, sizeof(digest)) != 0) { | ||
70 | error("%s: digest_memory failed", __func__); | ||
71 | return -1; | ||
72 | } | 82 | } |
73 | 83 | if ((ret = sshbuf_put_bignum2(bb, sig->r)) != 0 || | |
74 | sig = ECDSA_do_sign(digest, dlen, key->ecdsa); | 84 | (ret = sshbuf_put_bignum2(bb, sig->s)) != 0) |
75 | explicit_bzero(digest, sizeof(digest)); | 85 | goto out; |
76 | 86 | if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 || | |
77 | if (sig == NULL) { | 87 | (ret = sshbuf_put_stringb(b, bb)) != 0) |
78 | error("%s: sign failed", __func__); | 88 | goto out; |
79 | return -1; | 89 | len = sshbuf_len(b); |
90 | if (sigp != NULL) { | ||
91 | if ((*sigp = malloc(len)) == NULL) { | ||
92 | ret = SSH_ERR_ALLOC_FAIL; | ||
93 | goto out; | ||
94 | } | ||
95 | memcpy(*sigp, sshbuf_ptr(b), len); | ||
80 | } | 96 | } |
81 | |||
82 | buffer_init(&bb); | ||
83 | buffer_put_bignum2(&bb, sig->r); | ||
84 | buffer_put_bignum2(&bb, sig->s); | ||
85 | ECDSA_SIG_free(sig); | ||
86 | |||
87 | buffer_init(&b); | ||
88 | buffer_put_cstring(&b, key_ssh_name_plain(key)); | ||
89 | buffer_put_string(&b, buffer_ptr(&bb), buffer_len(&bb)); | ||
90 | buffer_free(&bb); | ||
91 | len = buffer_len(&b); | ||
92 | if (lenp != NULL) | 97 | if (lenp != NULL) |
93 | *lenp = len; | 98 | *lenp = len; |
94 | if (sigp != NULL) { | 99 | ret = 0; |
95 | *sigp = xmalloc(len); | 100 | out: |
96 | memcpy(*sigp, buffer_ptr(&b), len); | 101 | explicit_bzero(digest, sizeof(digest)); |
97 | } | 102 | if (b != NULL) |
98 | buffer_free(&b); | 103 | sshbuf_free(b); |
99 | 104 | if (bb != NULL) | |
100 | return 0; | 105 | sshbuf_free(bb); |
106 | if (sig != NULL) | ||
107 | ECDSA_SIG_free(sig); | ||
108 | return ret; | ||
101 | } | 109 | } |
110 | |||
111 | /* ARGSUSED */ | ||
102 | int | 112 | int |
103 | ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen, | 113 | ssh_ecdsa_verify(const struct sshkey *key, |
104 | const u_char *data, u_int datalen) | 114 | const u_char *signature, size_t signaturelen, |
115 | const u_char *data, size_t datalen, u_int compat) | ||
105 | { | 116 | { |
106 | ECDSA_SIG *sig; | 117 | ECDSA_SIG *sig = NULL; |
107 | int hash_alg; | 118 | int hash_alg; |
108 | u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; | 119 | u_char digest[SSH_DIGEST_MAX_LENGTH]; |
109 | u_int len, dlen; | 120 | size_t dlen; |
110 | int rlen, ret; | 121 | int ret = SSH_ERR_INTERNAL_ERROR; |
111 | Buffer b, bb; | 122 | struct sshbuf *b = NULL, *sigbuf = NULL; |
112 | char *ktype; | 123 | char *ktype = NULL; |
113 | 124 | ||
114 | if (key == NULL || key_type_plain(key->type) != KEY_ECDSA || | 125 | if (key == NULL || key->ecdsa == NULL || |
115 | key->ecdsa == NULL) { | 126 | sshkey_type_plain(key->type) != KEY_ECDSA) |
116 | error("%s: no ECDSA key", __func__); | 127 | return SSH_ERR_INVALID_ARGUMENT; |
117 | return -1; | 128 | |
118 | } | 129 | if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || |
130 | (dlen = ssh_digest_bytes(hash_alg)) == 0) | ||
131 | return SSH_ERR_INTERNAL_ERROR; | ||
119 | 132 | ||
120 | /* fetch signature */ | 133 | /* fetch signature */ |
121 | buffer_init(&b); | 134 | if ((b = sshbuf_from(signature, signaturelen)) == NULL) |
122 | buffer_append(&b, signature, signaturelen); | 135 | return SSH_ERR_ALLOC_FAIL; |
123 | ktype = buffer_get_string(&b, NULL); | 136 | if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || |
124 | if (strcmp(key_ssh_name_plain(key), ktype) != 0) { | 137 | sshbuf_froms(b, &sigbuf) != 0) { |
125 | error("%s: cannot handle type %s", __func__, ktype); | 138 | ret = SSH_ERR_INVALID_FORMAT; |
126 | buffer_free(&b); | 139 | goto out; |
127 | free(ktype); | ||
128 | return -1; | ||
129 | } | 140 | } |
130 | free(ktype); | 141 | if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) { |
131 | sigblob = buffer_get_string(&b, &len); | 142 | ret = SSH_ERR_KEY_TYPE_MISMATCH; |
132 | rlen = buffer_len(&b); | 143 | goto out; |
133 | buffer_free(&b); | 144 | } |
134 | if (rlen != 0) { | 145 | if (sshbuf_len(b) != 0) { |
135 | error("%s: remaining bytes in signature %d", __func__, rlen); | 146 | ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; |
136 | free(sigblob); | 147 | goto out; |
137 | return -1; | ||
138 | } | 148 | } |
139 | 149 | ||
140 | /* parse signature */ | 150 | /* parse signature */ |
141 | if ((sig = ECDSA_SIG_new()) == NULL) | 151 | if ((sig = ECDSA_SIG_new()) == NULL) { |
142 | fatal("%s: ECDSA_SIG_new failed", __func__); | 152 | ret = SSH_ERR_ALLOC_FAIL; |
143 | 153 | goto out; | |
144 | buffer_init(&bb); | 154 | } |
145 | buffer_append(&bb, sigblob, len); | 155 | if (sshbuf_get_bignum2(sigbuf, sig->r) != 0 || |
146 | buffer_get_bignum2(&bb, sig->r); | 156 | sshbuf_get_bignum2(sigbuf, sig->s) != 0) { |
147 | buffer_get_bignum2(&bb, sig->s); | 157 | ret = SSH_ERR_INVALID_FORMAT; |
148 | if (buffer_len(&bb) != 0) | 158 | goto out; |
149 | fatal("%s: remaining bytes in inner sigblob", __func__); | 159 | } |
150 | buffer_free(&bb); | 160 | if (sshbuf_len(sigbuf) != 0) { |
151 | 161 | ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; | |
152 | /* clean up */ | 162 | goto out; |
153 | explicit_bzero(sigblob, len); | ||
154 | free(sigblob); | ||
155 | |||
156 | /* hash the data */ | ||
157 | hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid); | ||
158 | if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { | ||
159 | error("%s: bad hash algorithm %d", __func__, hash_alg); | ||
160 | return -1; | ||
161 | } | 163 | } |
162 | if (ssh_digest_memory(hash_alg, data, datalen, | 164 | if ((ret = ssh_digest_memory(hash_alg, data, datalen, |
163 | digest, sizeof(digest)) != 0) { | 165 | digest, sizeof(digest))) != 0) |
164 | error("%s: digest_memory failed", __func__); | 166 | goto out; |
165 | return -1; | 167 | |
168 | switch (ECDSA_do_verify(digest, dlen, sig, key->ecdsa)) { | ||
169 | case 1: | ||
170 | ret = 0; | ||
171 | break; | ||
172 | case 0: | ||
173 | ret = SSH_ERR_SIGNATURE_INVALID; | ||
174 | goto out; | ||
175 | default: | ||
176 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
177 | goto out; | ||
166 | } | 178 | } |
167 | 179 | ||
168 | ret = ECDSA_do_verify(digest, dlen, sig, key->ecdsa); | 180 | out: |
169 | explicit_bzero(digest, sizeof(digest)); | 181 | explicit_bzero(digest, sizeof(digest)); |
170 | 182 | if (sigbuf != NULL) | |
171 | ECDSA_SIG_free(sig); | 183 | sshbuf_free(sigbuf); |
172 | 184 | if (b != NULL) | |
173 | debug("%s: signature %s", __func__, | 185 | sshbuf_free(b); |
174 | ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); | 186 | if (sig != NULL) |
187 | ECDSA_SIG_free(sig); | ||
188 | free(ktype); | ||
175 | return ret; | 189 | return ret; |
176 | } | 190 | } |
177 | 191 | ||
diff --git a/ssh-ed25519.c b/ssh-ed25519.c index 160d1f23b..cb87d4790 100644 --- a/ssh-ed25519.c +++ b/ssh-ed25519.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-ed25519.c,v 1.3 2014/02/23 20:03:42 djm Exp $ */ | 1 | /* $OpenBSD: ssh-ed25519.c,v 1.4 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2013 Markus Friedl <markus@openbsd.org> | 3 | * Copyright (c) 2013 Markus Friedl <markus@openbsd.org> |
4 | * | 4 | * |
@@ -18,132 +18,149 @@ | |||
18 | #include "includes.h" | 18 | #include "includes.h" |
19 | 19 | ||
20 | #include <sys/types.h> | 20 | #include <sys/types.h> |
21 | #include <limits.h> | ||
21 | 22 | ||
22 | #include "crypto_api.h" | 23 | #include "crypto_api.h" |
23 | 24 | ||
24 | #include <limits.h> | ||
25 | #include <string.h> | 25 | #include <string.h> |
26 | #include <stdarg.h> | 26 | #include <stdarg.h> |
27 | 27 | ||
28 | #include "xmalloc.h" | 28 | #include "xmalloc.h" |
29 | #include "log.h" | 29 | #include "log.h" |
30 | #include "buffer.h" | 30 | #include "buffer.h" |
31 | #include "key.h" | 31 | #define SSHKEY_INTERNAL |
32 | #include "sshkey.h" | ||
33 | #include "ssherr.h" | ||
32 | #include "ssh.h" | 34 | #include "ssh.h" |
33 | 35 | ||
34 | int | 36 | int |
35 | ssh_ed25519_sign(const Key *key, u_char **sigp, u_int *lenp, | 37 | ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
36 | const u_char *data, u_int datalen) | 38 | const u_char *data, size_t datalen, u_int compat) |
37 | { | 39 | { |
38 | u_char *sig; | 40 | u_char *sig = NULL; |
39 | u_int slen, len; | 41 | size_t slen = 0, len; |
40 | unsigned long long smlen; | 42 | unsigned long long smlen; |
41 | int ret; | 43 | int r, ret; |
42 | Buffer b; | 44 | struct sshbuf *b = NULL; |
43 | 45 | ||
44 | if (key == NULL || key_type_plain(key->type) != KEY_ED25519 || | 46 | if (lenp != NULL) |
45 | key->ed25519_sk == NULL) { | 47 | *lenp = 0; |
46 | error("%s: no ED25519 key", __func__); | 48 | if (sigp != NULL) |
47 | return -1; | 49 | *sigp = NULL; |
48 | } | ||
49 | 50 | ||
50 | if (datalen >= UINT_MAX - crypto_sign_ed25519_BYTES) { | 51 | if (key == NULL || |
51 | error("%s: datalen %u too long", __func__, datalen); | 52 | sshkey_type_plain(key->type) != KEY_ED25519 || |
52 | return -1; | 53 | key->ed25519_sk == NULL || |
53 | } | 54 | datalen >= INT_MAX - crypto_sign_ed25519_BYTES) |
55 | return SSH_ERR_INVALID_ARGUMENT; | ||
54 | smlen = slen = datalen + crypto_sign_ed25519_BYTES; | 56 | smlen = slen = datalen + crypto_sign_ed25519_BYTES; |
55 | sig = xmalloc(slen); | 57 | if ((sig = malloc(slen)) == NULL) |
58 | return SSH_ERR_ALLOC_FAIL; | ||
56 | 59 | ||
57 | if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen, | 60 | if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen, |
58 | key->ed25519_sk)) != 0 || smlen <= datalen) { | 61 | key->ed25519_sk)) != 0 || smlen <= datalen) { |
59 | error("%s: crypto_sign_ed25519 failed: %d", __func__, ret); | 62 | r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */ |
60 | free(sig); | 63 | goto out; |
61 | return -1; | ||
62 | } | 64 | } |
63 | /* encode signature */ | 65 | /* encode signature */ |
64 | buffer_init(&b); | 66 | if ((b = sshbuf_new()) == NULL) { |
65 | buffer_put_cstring(&b, "ssh-ed25519"); | 67 | r = SSH_ERR_ALLOC_FAIL; |
66 | buffer_put_string(&b, sig, smlen - datalen); | 68 | goto out; |
67 | len = buffer_len(&b); | 69 | } |
70 | if ((r = sshbuf_put_cstring(b, "ssh-ed25519")) != 0 || | ||
71 | (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0) | ||
72 | goto out; | ||
73 | len = sshbuf_len(b); | ||
74 | if (sigp != NULL) { | ||
75 | if ((*sigp = malloc(len)) == NULL) { | ||
76 | r = SSH_ERR_ALLOC_FAIL; | ||
77 | goto out; | ||
78 | } | ||
79 | memcpy(*sigp, sshbuf_ptr(b), len); | ||
80 | } | ||
68 | if (lenp != NULL) | 81 | if (lenp != NULL) |
69 | *lenp = len; | 82 | *lenp = len; |
70 | if (sigp != NULL) { | 83 | /* success */ |
71 | *sigp = xmalloc(len); | 84 | r = 0; |
72 | memcpy(*sigp, buffer_ptr(&b), len); | 85 | out: |
86 | sshbuf_free(b); | ||
87 | if (sig != NULL) { | ||
88 | explicit_bzero(sig, slen); | ||
89 | free(sig); | ||
73 | } | 90 | } |
74 | buffer_free(&b); | ||
75 | explicit_bzero(sig, slen); | ||
76 | free(sig); | ||
77 | 91 | ||
78 | return 0; | 92 | return r; |
79 | } | 93 | } |
80 | 94 | ||
81 | int | 95 | int |
82 | ssh_ed25519_verify(const Key *key, const u_char *signature, u_int signaturelen, | 96 | ssh_ed25519_verify(const struct sshkey *key, |
83 | const u_char *data, u_int datalen) | 97 | const u_char *signature, size_t signaturelen, |
98 | const u_char *data, size_t datalen, u_int compat) | ||
84 | { | 99 | { |
85 | Buffer b; | 100 | struct sshbuf *b = NULL; |
86 | char *ktype; | 101 | char *ktype = NULL; |
87 | u_char *sigblob, *sm, *m; | 102 | const u_char *sigblob; |
88 | u_int len; | 103 | u_char *sm = NULL, *m = NULL; |
89 | unsigned long long smlen, mlen; | 104 | size_t len; |
90 | int rlen, ret; | 105 | unsigned long long smlen = 0, mlen = 0; |
106 | int r, ret; | ||
91 | 107 | ||
92 | if (key == NULL || key_type_plain(key->type) != KEY_ED25519 || | 108 | if (key == NULL || |
93 | key->ed25519_pk == NULL) { | 109 | sshkey_type_plain(key->type) != KEY_ED25519 || |
94 | error("%s: no ED25519 key", __func__); | 110 | key->ed25519_pk == NULL || |
95 | return -1; | 111 | datalen >= INT_MAX - crypto_sign_ed25519_BYTES) |
96 | } | 112 | return SSH_ERR_INVALID_ARGUMENT; |
97 | buffer_init(&b); | 113 | |
98 | buffer_append(&b, signature, signaturelen); | 114 | if ((b = sshbuf_from(signature, signaturelen)) == NULL) |
99 | ktype = buffer_get_cstring(&b, NULL); | 115 | return SSH_ERR_ALLOC_FAIL; |
116 | if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 || | ||
117 | (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0) | ||
118 | goto out; | ||
100 | if (strcmp("ssh-ed25519", ktype) != 0) { | 119 | if (strcmp("ssh-ed25519", ktype) != 0) { |
101 | error("%s: cannot handle type %s", __func__, ktype); | 120 | r = SSH_ERR_KEY_TYPE_MISMATCH; |
102 | buffer_free(&b); | 121 | goto out; |
103 | free(ktype); | ||
104 | return -1; | ||
105 | } | 122 | } |
106 | free(ktype); | 123 | if (sshbuf_len(b) != 0) { |
107 | sigblob = buffer_get_string(&b, &len); | 124 | r = SSH_ERR_UNEXPECTED_TRAILING_DATA; |
108 | rlen = buffer_len(&b); | 125 | goto out; |
109 | buffer_free(&b); | ||
110 | if (rlen != 0) { | ||
111 | error("%s: remaining bytes in signature %d", __func__, rlen); | ||
112 | free(sigblob); | ||
113 | return -1; | ||
114 | } | 126 | } |
115 | if (len > crypto_sign_ed25519_BYTES) { | 127 | if (len > crypto_sign_ed25519_BYTES) { |
116 | error("%s: len %u > crypto_sign_ed25519_BYTES %u", __func__, | 128 | r = SSH_ERR_INVALID_FORMAT; |
117 | len, crypto_sign_ed25519_BYTES); | 129 | goto out; |
118 | free(sigblob); | ||
119 | return -1; | ||
120 | } | 130 | } |
131 | if (datalen >= SIZE_MAX - len) | ||
132 | return SSH_ERR_INVALID_ARGUMENT; | ||
121 | smlen = len + datalen; | 133 | smlen = len + datalen; |
122 | sm = xmalloc(smlen); | 134 | mlen = smlen; |
135 | if ((sm = malloc(smlen)) == NULL || (m = xmalloc(mlen)) == NULL) { | ||
136 | r = SSH_ERR_ALLOC_FAIL; | ||
137 | goto out; | ||
138 | } | ||
123 | memcpy(sm, sigblob, len); | 139 | memcpy(sm, sigblob, len); |
124 | memcpy(sm+len, data, datalen); | 140 | memcpy(sm+len, data, datalen); |
125 | mlen = smlen; | ||
126 | m = xmalloc(mlen); | ||
127 | if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, | 141 | if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, |
128 | key->ed25519_pk)) != 0) { | 142 | key->ed25519_pk)) != 0) { |
129 | debug2("%s: crypto_sign_ed25519_open failed: %d", | 143 | debug2("%s: crypto_sign_ed25519_open failed: %d", |
130 | __func__, ret); | 144 | __func__, ret); |
131 | } | 145 | } |
132 | if (ret == 0 && mlen != datalen) { | 146 | if (ret != 0 || mlen != datalen) { |
133 | debug2("%s: crypto_sign_ed25519_open " | 147 | r = SSH_ERR_SIGNATURE_INVALID; |
134 | "mlen != datalen (%llu != %u)", __func__, mlen, datalen); | 148 | goto out; |
135 | ret = -1; | ||
136 | } | 149 | } |
137 | /* XXX compare 'm' and 'data' ? */ | 150 | /* XXX compare 'm' and 'data' ? */ |
138 | 151 | /* success */ | |
139 | explicit_bzero(sigblob, len); | 152 | r = 0; |
140 | explicit_bzero(sm, smlen); | 153 | out: |
141 | explicit_bzero(m, smlen); /* NB. mlen may be invalid if ret != 0 */ | 154 | if (sm != NULL) { |
142 | free(sigblob); | 155 | explicit_bzero(sm, smlen); |
143 | free(sm); | 156 | free(sm); |
144 | free(m); | 157 | } |
145 | debug("%s: signature %scorrect", __func__, (ret != 0) ? "in" : ""); | 158 | if (m != NULL) { |
146 | 159 | explicit_bzero(m, smlen); /* NB mlen may be invalid if r != 0 */ | |
147 | /* translate return code carefully */ | 160 | free(m); |
148 | return (ret == 0) ? 1 : -1; | 161 | } |
162 | sshbuf_free(b); | ||
163 | free(ktype); | ||
164 | return r; | ||
149 | } | 165 | } |
166 | |||
diff --git a/ssh-keygen.c b/ssh-keygen.c index 085f1ec55..e2aa215b2 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.246 2014/04/29 18:01:49 markus Exp $ */ | 1 | /* $OpenBSD: ssh-keygen.c,v 1.247 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -482,7 +482,9 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) | |||
482 | buffer_get_bignum_bits(&b, key->rsa->iqmp); | 482 | buffer_get_bignum_bits(&b, key->rsa->iqmp); |
483 | buffer_get_bignum_bits(&b, key->rsa->q); | 483 | buffer_get_bignum_bits(&b, key->rsa->q); |
484 | buffer_get_bignum_bits(&b, key->rsa->p); | 484 | buffer_get_bignum_bits(&b, key->rsa->p); |
485 | rsa_generate_additional_parameters(key->rsa); | 485 | if (rsa_generate_additional_parameters(key->rsa) != 0) |
486 | fatal("%s: rsa_generate_additional_parameters " | ||
487 | "error", __func__); | ||
486 | break; | 488 | break; |
487 | } | 489 | } |
488 | rlen = buffer_len(&b); | 490 | rlen = buffer_len(&b); |
@@ -1637,12 +1639,12 @@ do_ca_sign(struct passwd *pw, int argc, char **argv) | |||
1637 | public->cert->valid_after = cert_valid_from; | 1639 | public->cert->valid_after = cert_valid_from; |
1638 | public->cert->valid_before = cert_valid_to; | 1640 | public->cert->valid_before = cert_valid_to; |
1639 | if (v00) { | 1641 | if (v00) { |
1640 | prepare_options_buf(&public->cert->critical, | 1642 | prepare_options_buf(public->cert->critical, |
1641 | OPTIONS_CRITICAL|OPTIONS_EXTENSIONS); | 1643 | OPTIONS_CRITICAL|OPTIONS_EXTENSIONS); |
1642 | } else { | 1644 | } else { |
1643 | prepare_options_buf(&public->cert->critical, | 1645 | prepare_options_buf(public->cert->critical, |
1644 | OPTIONS_CRITICAL); | 1646 | OPTIONS_CRITICAL); |
1645 | prepare_options_buf(&public->cert->extensions, | 1647 | prepare_options_buf(public->cert->extensions, |
1646 | OPTIONS_EXTENSIONS); | 1648 | OPTIONS_EXTENSIONS); |
1647 | } | 1649 | } |
1648 | public->cert->signature_key = key_from_private(ca); | 1650 | public->cert->signature_key = key_from_private(ca); |
@@ -1913,19 +1915,19 @@ do_show_cert(struct passwd *pw) | |||
1913 | printf("\n"); | 1915 | printf("\n"); |
1914 | } | 1916 | } |
1915 | printf(" Critical Options: "); | 1917 | printf(" Critical Options: "); |
1916 | if (buffer_len(&key->cert->critical) == 0) | 1918 | if (buffer_len(key->cert->critical) == 0) |
1917 | printf("(none)\n"); | 1919 | printf("(none)\n"); |
1918 | else { | 1920 | else { |
1919 | printf("\n"); | 1921 | printf("\n"); |
1920 | show_options(&key->cert->critical, v00, 1); | 1922 | show_options(key->cert->critical, v00, 1); |
1921 | } | 1923 | } |
1922 | if (!v00) { | 1924 | if (!v00) { |
1923 | printf(" Extensions: "); | 1925 | printf(" Extensions: "); |
1924 | if (buffer_len(&key->cert->extensions) == 0) | 1926 | if (buffer_len(key->cert->extensions) == 0) |
1925 | printf("(none)\n"); | 1927 | printf("(none)\n"); |
1926 | else { | 1928 | else { |
1927 | printf("\n"); | 1929 | printf("\n"); |
1928 | show_options(&key->cert->extensions, v00, 0); | 1930 | show_options(key->cert->extensions, v00, 0); |
1929 | } | 1931 | } |
1930 | } | 1932 | } |
1931 | exit(0); | 1933 | exit(0); |
diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index 6c9f9d2c1..8c74864aa 100644 --- a/ssh-pkcs11-client.c +++ b/ssh-pkcs11-client.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-pkcs11-client.c,v 1.4 2013/05/17 00:13:14 djm Exp $ */ | 1 | /* $OpenBSD: ssh-pkcs11-client.c,v 1.5 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2010 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2010 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -30,6 +30,8 @@ | |||
30 | #include <unistd.h> | 30 | #include <unistd.h> |
31 | #include <errno.h> | 31 | #include <errno.h> |
32 | 32 | ||
33 | #include <openssl/rsa.h> | ||
34 | |||
33 | #include "pathnames.h" | 35 | #include "pathnames.h" |
34 | #include "xmalloc.h" | 36 | #include "xmalloc.h" |
35 | #include "buffer.h" | 37 | #include "buffer.h" |
diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c index b7c52beb8..0b1d8e4cc 100644 --- a/ssh-pkcs11-helper.c +++ b/ssh-pkcs11-helper.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-pkcs11-helper.c,v 1.7 2013/12/02 02:56:17 djm Exp $ */ | 1 | /* $OpenBSD: ssh-pkcs11-helper.c,v 1.8 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2010 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2010 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -169,7 +169,7 @@ process_sign(void) | |||
169 | { | 169 | { |
170 | u_char *blob, *data, *signature = NULL; | 170 | u_char *blob, *data, *signature = NULL; |
171 | u_int blen, dlen, slen = 0; | 171 | u_int blen, dlen, slen = 0; |
172 | int ok = -1, ret; | 172 | int ok = -1; |
173 | Key *key, *found; | 173 | Key *key, *found; |
174 | Buffer msg; | 174 | Buffer msg; |
175 | 175 | ||
@@ -179,6 +179,9 @@ process_sign(void) | |||
179 | 179 | ||
180 | if ((key = key_from_blob(blob, blen)) != NULL) { | 180 | if ((key = key_from_blob(blob, blen)) != NULL) { |
181 | if ((found = lookup_key(key)) != NULL) { | 181 | if ((found = lookup_key(key)) != NULL) { |
182 | #ifdef WITH_OPENSSL | ||
183 | int ret; | ||
184 | |||
182 | slen = RSA_size(key->rsa); | 185 | slen = RSA_size(key->rsa); |
183 | signature = xmalloc(slen); | 186 | signature = xmalloc(slen); |
184 | if ((ret = RSA_private_encrypt(dlen, data, signature, | 187 | if ((ret = RSA_private_encrypt(dlen, data, signature, |
@@ -186,6 +189,7 @@ process_sign(void) | |||
186 | slen = ret; | 189 | slen = ret; |
187 | ok = 0; | 190 | ok = 0; |
188 | } | 191 | } |
192 | #endif /* WITH_OPENSSL */ | ||
189 | } | 193 | } |
190 | key_free(key); | 194 | key_free(key); |
191 | } | 195 | } |
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index d3e877291..c96be3bd2 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-pkcs11.c,v 1.13 2014/05/02 03:27:54 djm Exp $ */ | 1 | /* $OpenBSD: ssh-pkcs11.c,v 1.14 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2010 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2010 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -520,7 +520,7 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, | |||
520 | key = key_new(KEY_UNSPEC); | 520 | key = key_new(KEY_UNSPEC); |
521 | key->rsa = rsa; | 521 | key->rsa = rsa; |
522 | key->type = KEY_RSA; | 522 | key->type = KEY_RSA; |
523 | key->flags |= KEY_FLAG_EXT; | 523 | key->flags |= SSHKEY_FLAG_EXT; |
524 | if (pkcs11_key_included(keysp, nkeys, key)) { | 524 | if (pkcs11_key_included(keysp, nkeys, key)) { |
525 | key_free(key); | 525 | key_free(key); |
526 | } else { | 526 | } else { |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-rsa.c,v 1.51 2014/02/02 03:44:31 djm Exp $ */ | 1 | /* $OpenBSD: ssh-rsa.c,v 1.52 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> | 3 | * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> |
4 | * | 4 | * |
@@ -25,163 +25,167 @@ | |||
25 | #include <stdarg.h> | 25 | #include <stdarg.h> |
26 | #include <string.h> | 26 | #include <string.h> |
27 | 27 | ||
28 | #include "xmalloc.h" | 28 | #include "sshbuf.h" |
29 | #include "log.h" | ||
30 | #include "buffer.h" | ||
31 | #include "key.h" | ||
32 | #include "compat.h" | 29 | #include "compat.h" |
33 | #include "misc.h" | 30 | #include "ssherr.h" |
34 | #include "ssh.h" | 31 | #define SSHKEY_INTERNAL |
32 | #include "sshkey.h" | ||
35 | #include "digest.h" | 33 | #include "digest.h" |
36 | 34 | ||
37 | static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *); | 35 | static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); |
38 | 36 | ||
39 | /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ | 37 | /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ |
40 | int | 38 | int |
41 | ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, | 39 | ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
42 | const u_char *data, u_int datalen) | 40 | const u_char *data, size_t datalen, u_int compat) |
43 | { | 41 | { |
44 | int hash_alg; | 42 | int hash_alg; |
45 | u_char digest[SSH_DIGEST_MAX_LENGTH], *sig; | 43 | u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; |
46 | u_int slen, dlen, len; | 44 | size_t slen; |
47 | int ok, nid; | 45 | u_int dlen, len; |
48 | Buffer b; | 46 | int nid, ret = SSH_ERR_INTERNAL_ERROR; |
47 | struct sshbuf *b = NULL; | ||
49 | 48 | ||
50 | if (key == NULL || key_type_plain(key->type) != KEY_RSA || | 49 | if (lenp != NULL) |
51 | key->rsa == NULL) { | 50 | *lenp = 0; |
52 | error("%s: no RSA key", __func__); | 51 | if (sigp != NULL) |
53 | return -1; | 52 | *sigp = NULL; |
54 | } | 53 | |
54 | if (key == NULL || key->rsa == NULL || | ||
55 | sshkey_type_plain(key->type) != KEY_RSA) | ||
56 | return SSH_ERR_INVALID_ARGUMENT; | ||
57 | slen = RSA_size(key->rsa); | ||
58 | if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) | ||
59 | return SSH_ERR_INVALID_ARGUMENT; | ||
55 | 60 | ||
56 | /* hash the data */ | 61 | /* hash the data */ |
57 | hash_alg = SSH_DIGEST_SHA1; | 62 | hash_alg = SSH_DIGEST_SHA1; |
58 | nid = NID_sha1; | 63 | nid = NID_sha1; |
59 | if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { | 64 | if ((dlen = ssh_digest_bytes(hash_alg)) == 0) |
60 | error("%s: bad hash algorithm %d", __func__, hash_alg); | 65 | return SSH_ERR_INTERNAL_ERROR; |
61 | return -1; | 66 | if ((ret = ssh_digest_memory(hash_alg, data, datalen, |
62 | } | 67 | digest, sizeof(digest))) != 0) |
63 | if (ssh_digest_memory(hash_alg, data, datalen, | 68 | goto out; |
64 | digest, sizeof(digest)) != 0) { | ||
65 | error("%s: ssh_digest_memory failed", __func__); | ||
66 | return -1; | ||
67 | } | ||
68 | |||
69 | slen = RSA_size(key->rsa); | ||
70 | sig = xmalloc(slen); | ||
71 | |||
72 | ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa); | ||
73 | explicit_bzero(digest, sizeof(digest)); | ||
74 | 69 | ||
75 | if (ok != 1) { | 70 | if ((sig = malloc(slen)) == NULL) { |
76 | int ecode = ERR_get_error(); | 71 | ret = SSH_ERR_ALLOC_FAIL; |
72 | goto out; | ||
73 | } | ||
77 | 74 | ||
78 | error("%s: RSA_sign failed: %s", __func__, | 75 | if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { |
79 | ERR_error_string(ecode, NULL)); | 76 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
80 | free(sig); | 77 | goto out; |
81 | return -1; | ||
82 | } | 78 | } |
83 | if (len < slen) { | 79 | if (len < slen) { |
84 | u_int diff = slen - len; | 80 | size_t diff = slen - len; |
85 | debug("slen %u > len %u", slen, len); | ||
86 | memmove(sig + diff, sig, len); | 81 | memmove(sig + diff, sig, len); |
87 | explicit_bzero(sig, diff); | 82 | explicit_bzero(sig, diff); |
88 | } else if (len > slen) { | 83 | } else if (len > slen) { |
89 | error("%s: slen %u slen2 %u", __func__, slen, len); | 84 | ret = SSH_ERR_INTERNAL_ERROR; |
90 | free(sig); | 85 | goto out; |
91 | return -1; | ||
92 | } | 86 | } |
93 | /* encode signature */ | 87 | /* encode signature */ |
94 | buffer_init(&b); | 88 | if ((b = sshbuf_new()) == NULL) { |
95 | buffer_put_cstring(&b, "ssh-rsa"); | 89 | ret = SSH_ERR_ALLOC_FAIL; |
96 | buffer_put_string(&b, sig, slen); | 90 | goto out; |
97 | len = buffer_len(&b); | 91 | } |
92 | if ((ret = sshbuf_put_cstring(b, "ssh-rsa")) != 0 || | ||
93 | (ret = sshbuf_put_string(b, sig, slen)) != 0) | ||
94 | goto out; | ||
95 | len = sshbuf_len(b); | ||
96 | if (sigp != NULL) { | ||
97 | if ((*sigp = malloc(len)) == NULL) { | ||
98 | ret = SSH_ERR_ALLOC_FAIL; | ||
99 | goto out; | ||
100 | } | ||
101 | memcpy(*sigp, sshbuf_ptr(b), len); | ||
102 | } | ||
98 | if (lenp != NULL) | 103 | if (lenp != NULL) |
99 | *lenp = len; | 104 | *lenp = len; |
100 | if (sigp != NULL) { | 105 | ret = 0; |
101 | *sigp = xmalloc(len); | 106 | out: |
102 | memcpy(*sigp, buffer_ptr(&b), len); | 107 | explicit_bzero(digest, sizeof(digest)); |
108 | if (sig != NULL) { | ||
109 | explicit_bzero(sig, slen); | ||
110 | free(sig); | ||
103 | } | 111 | } |
104 | buffer_free(&b); | 112 | if (b != NULL) |
105 | explicit_bzero(sig, slen); | 113 | sshbuf_free(b); |
106 | free(sig); | ||
107 | |||
108 | return 0; | 114 | return 0; |
109 | } | 115 | } |
110 | 116 | ||
111 | int | 117 | int |
112 | ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, | 118 | ssh_rsa_verify(const struct sshkey *key, |
113 | const u_char *data, u_int datalen) | 119 | const u_char *signature, size_t signaturelen, |
120 | const u_char *data, size_t datalen, u_int compat) | ||
114 | { | 121 | { |
115 | Buffer b; | 122 | char *ktype = NULL; |
116 | int hash_alg; | 123 | int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; |
117 | char *ktype; | 124 | size_t len, diff, modlen, dlen; |
118 | u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; | 125 | struct sshbuf *b = NULL; |
119 | u_int len, dlen, modlen; | 126 | u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; |
120 | int rlen, ret; | ||
121 | 127 | ||
122 | if (key == NULL || key_type_plain(key->type) != KEY_RSA || | 128 | if (key == NULL || key->rsa == NULL || |
123 | key->rsa == NULL) { | 129 | sshkey_type_plain(key->type) != KEY_RSA || |
124 | error("%s: no RSA key", __func__); | 130 | BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) |
125 | return -1; | 131 | return SSH_ERR_INVALID_ARGUMENT; |
126 | } | ||
127 | 132 | ||
128 | if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { | 133 | if ((b = sshbuf_from(signature, signaturelen)) == NULL) |
129 | error("%s: RSA modulus too small: %d < minimum %d bits", | 134 | return SSH_ERR_ALLOC_FAIL; |
130 | __func__, BN_num_bits(key->rsa->n), | 135 | if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { |
131 | SSH_RSA_MINIMUM_MODULUS_SIZE); | 136 | ret = SSH_ERR_INVALID_FORMAT; |
132 | return -1; | 137 | goto out; |
133 | } | 138 | } |
134 | buffer_init(&b); | ||
135 | buffer_append(&b, signature, signaturelen); | ||
136 | ktype = buffer_get_cstring(&b, NULL); | ||
137 | if (strcmp("ssh-rsa", ktype) != 0) { | 139 | if (strcmp("ssh-rsa", ktype) != 0) { |
138 | error("%s: cannot handle type %s", __func__, ktype); | 140 | ret = SSH_ERR_KEY_TYPE_MISMATCH; |
139 | buffer_free(&b); | 141 | goto out; |
140 | free(ktype); | ||
141 | return -1; | ||
142 | } | 142 | } |
143 | free(ktype); | 143 | if (sshbuf_get_string(b, &sigblob, &len) != 0) { |
144 | sigblob = buffer_get_string(&b, &len); | 144 | ret = SSH_ERR_INVALID_FORMAT; |
145 | rlen = buffer_len(&b); | 145 | goto out; |
146 | buffer_free(&b); | 146 | } |
147 | if (rlen != 0) { | 147 | if (sshbuf_len(b) != 0) { |
148 | error("%s: remaining bytes in signature %d", __func__, rlen); | 148 | ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; |
149 | free(sigblob); | 149 | goto out; |
150 | return -1; | ||
151 | } | 150 | } |
152 | /* RSA_verify expects a signature of RSA_size */ | 151 | /* RSA_verify expects a signature of RSA_size */ |
153 | modlen = RSA_size(key->rsa); | 152 | modlen = RSA_size(key->rsa); |
154 | if (len > modlen) { | 153 | if (len > modlen) { |
155 | error("%s: len %u > modlen %u", __func__, len, modlen); | 154 | ret = SSH_ERR_KEY_BITS_MISMATCH; |
156 | free(sigblob); | 155 | goto out; |
157 | return -1; | ||
158 | } else if (len < modlen) { | 156 | } else if (len < modlen) { |
159 | u_int diff = modlen - len; | 157 | diff = modlen - len; |
160 | debug("%s: add padding: modlen %u > len %u", __func__, | 158 | osigblob = sigblob; |
161 | modlen, len); | 159 | if ((sigblob = realloc(sigblob, modlen)) == NULL) { |
162 | sigblob = xrealloc(sigblob, 1, modlen); | 160 | sigblob = osigblob; /* put it back for clear/free */ |
161 | ret = SSH_ERR_ALLOC_FAIL; | ||
162 | goto out; | ||
163 | } | ||
163 | memmove(sigblob + diff, sigblob, len); | 164 | memmove(sigblob + diff, sigblob, len); |
164 | explicit_bzero(sigblob, diff); | 165 | explicit_bzero(sigblob, diff); |
165 | len = modlen; | 166 | len = modlen; |
166 | } | 167 | } |
167 | /* hash the data */ | ||
168 | hash_alg = SSH_DIGEST_SHA1; | 168 | hash_alg = SSH_DIGEST_SHA1; |
169 | if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { | 169 | if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { |
170 | error("%s: bad hash algorithm %d", __func__, hash_alg); | 170 | ret = SSH_ERR_INTERNAL_ERROR; |
171 | return -1; | 171 | goto out; |
172 | } | ||
173 | if (ssh_digest_memory(hash_alg, data, datalen, | ||
174 | digest, sizeof(digest)) != 0) { | ||
175 | error("%s: ssh_digest_memory failed", __func__); | ||
176 | return -1; | ||
177 | } | 172 | } |
173 | if ((ret = ssh_digest_memory(hash_alg, data, datalen, | ||
174 | digest, sizeof(digest))) != 0) | ||
175 | goto out; | ||
178 | 176 | ||
179 | ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, | 177 | ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, |
180 | key->rsa); | 178 | key->rsa); |
179 | out: | ||
180 | if (sigblob != NULL) { | ||
181 | explicit_bzero(sigblob, len); | ||
182 | free(sigblob); | ||
183 | } | ||
184 | if (ktype != NULL) | ||
185 | free(ktype); | ||
186 | if (b != NULL) | ||
187 | sshbuf_free(b); | ||
181 | explicit_bzero(digest, sizeof(digest)); | 188 | explicit_bzero(digest, sizeof(digest)); |
182 | explicit_bzero(sigblob, len); | ||
183 | free(sigblob); | ||
184 | debug("%s: signature %scorrect", __func__, (ret == 0) ? "in" : ""); | ||
185 | return ret; | 189 | return ret; |
186 | } | 190 | } |
187 | 191 | ||
@@ -204,15 +208,15 @@ static const u_char id_sha1[] = { | |||
204 | }; | 208 | }; |
205 | 209 | ||
206 | static int | 210 | static int |
207 | openssh_RSA_verify(int hash_alg, u_char *hash, u_int hashlen, | 211 | openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, |
208 | u_char *sigbuf, u_int siglen, RSA *rsa) | 212 | u_char *sigbuf, size_t siglen, RSA *rsa) |
209 | { | 213 | { |
210 | u_int ret, rsasize, oidlen = 0, hlen = 0; | 214 | size_t ret, rsasize = 0, oidlen = 0, hlen = 0; |
211 | int len, oidmatch, hashmatch; | 215 | int len, oidmatch, hashmatch; |
212 | const u_char *oid = NULL; | 216 | const u_char *oid = NULL; |
213 | u_char *decrypted = NULL; | 217 | u_char *decrypted = NULL; |
214 | 218 | ||
215 | ret = 0; | 219 | ret = SSH_ERR_INTERNAL_ERROR; |
216 | switch (hash_alg) { | 220 | switch (hash_alg) { |
217 | case SSH_DIGEST_SHA1: | 221 | case SSH_DIGEST_SHA1: |
218 | oid = id_sha1; | 222 | oid = id_sha1; |
@@ -223,37 +227,39 @@ openssh_RSA_verify(int hash_alg, u_char *hash, u_int hashlen, | |||
223 | goto done; | 227 | goto done; |
224 | } | 228 | } |
225 | if (hashlen != hlen) { | 229 | if (hashlen != hlen) { |
226 | error("bad hashlen"); | 230 | ret = SSH_ERR_INVALID_ARGUMENT; |
227 | goto done; | 231 | goto done; |
228 | } | 232 | } |
229 | rsasize = RSA_size(rsa); | 233 | rsasize = RSA_size(rsa); |
230 | if (siglen == 0 || siglen > rsasize) { | 234 | if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || |
231 | error("bad siglen"); | 235 | siglen == 0 || siglen > rsasize) { |
236 | ret = SSH_ERR_INVALID_ARGUMENT; | ||
237 | goto done; | ||
238 | } | ||
239 | if ((decrypted = malloc(rsasize)) == NULL) { | ||
240 | ret = SSH_ERR_ALLOC_FAIL; | ||
232 | goto done; | 241 | goto done; |
233 | } | 242 | } |
234 | decrypted = xmalloc(rsasize); | ||
235 | if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, | 243 | if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, |
236 | RSA_PKCS1_PADDING)) < 0) { | 244 | RSA_PKCS1_PADDING)) < 0) { |
237 | error("RSA_public_decrypt failed: %s", | 245 | ret = SSH_ERR_LIBCRYPTO_ERROR; |
238 | ERR_error_string(ERR_get_error(), NULL)); | ||
239 | goto done; | 246 | goto done; |
240 | } | 247 | } |
241 | if (len < 0 || (u_int)len != hlen + oidlen) { | 248 | if (len < 0 || (size_t)len != hlen + oidlen) { |
242 | error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); | 249 | ret = SSH_ERR_INVALID_FORMAT; |
243 | goto done; | 250 | goto done; |
244 | } | 251 | } |
245 | oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; | 252 | oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; |
246 | hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; | 253 | hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; |
247 | if (!oidmatch) { | 254 | if (!oidmatch || !hashmatch) { |
248 | error("oid mismatch"); | 255 | ret = SSH_ERR_SIGNATURE_INVALID; |
249 | goto done; | ||
250 | } | ||
251 | if (!hashmatch) { | ||
252 | error("hash mismatch"); | ||
253 | goto done; | 256 | goto done; |
254 | } | 257 | } |
255 | ret = 1; | 258 | ret = 0; |
256 | done: | 259 | done: |
257 | free(decrypted); | 260 | if (decrypted) { |
261 | explicit_bzero(decrypted, rsasize); | ||
262 | free(decrypted); | ||
263 | } | ||
258 | return ret; | 264 | return ret; |
259 | } | 265 | } |
diff --git a/sshbuf-misc.c b/sshbuf-misc.c index 22dbfd5a4..bfeffe674 100644 --- a/sshbuf-misc.c +++ b/sshbuf-misc.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshbuf-misc.c,v 1.1 2014/04/30 05:29:56 djm Exp $ */ | 1 | /* $OpenBSD: sshbuf-misc.c,v 1.2 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2011 Damien Miller | 3 | * Copyright (c) 2011 Damien Miller |
4 | * | 4 | * |
@@ -33,12 +33,11 @@ | |||
33 | #include "sshbuf.h" | 33 | #include "sshbuf.h" |
34 | 34 | ||
35 | void | 35 | void |
36 | sshbuf_dump(struct sshbuf *buf, FILE *f) | 36 | sshbuf_dump_data(const void *s, size_t len, FILE *f) |
37 | { | 37 | { |
38 | const u_char *p = sshbuf_ptr(buf); | 38 | size_t i, j; |
39 | size_t i, j, len = sshbuf_len(buf); | 39 | const u_char *p = (const u_char *)s; |
40 | 40 | ||
41 | fprintf(f, "buffer %p len = %zu\n", buf, len); | ||
42 | for (i = 0; i < len; i += 16) { | 41 | for (i = 0; i < len; i += 16) { |
43 | fprintf(f, "%.4zd: ", i); | 42 | fprintf(f, "%.4zd: ", i); |
44 | for (j = i; j < i + 16; j++) { | 43 | for (j = i; j < i + 16; j++) { |
@@ -60,6 +59,13 @@ sshbuf_dump(struct sshbuf *buf, FILE *f) | |||
60 | } | 59 | } |
61 | } | 60 | } |
62 | 61 | ||
62 | void | ||
63 | sshbuf_dump(struct sshbuf *buf, FILE *f) | ||
64 | { | ||
65 | fprintf(f, "buffer %p len = %zu\n", buf, sshbuf_len(buf)); | ||
66 | sshbuf_dump_data(sshbuf_ptr(buf), sshbuf_len(buf), f); | ||
67 | } | ||
68 | |||
63 | char * | 69 | char * |
64 | sshbuf_dtob16(struct sshbuf *buf) | 70 | sshbuf_dtob16(struct sshbuf *buf) |
65 | { | 71 | { |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshbuf.h,v 1.2 2014/06/10 21:46:11 dtucker Exp $ */ | 1 | /* $OpenBSD: sshbuf.h,v 1.3 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2011 Damien Miller | 3 | * Copyright (c) 2011 Damien Miller |
4 | * | 4 | * |
@@ -216,9 +216,12 @@ int sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g); | |||
216 | int sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v); | 216 | int sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v); |
217 | #endif | 217 | #endif |
218 | 218 | ||
219 | /* Dump the contents of the buffer to stderr in a human-readable format */ | 219 | /* Dump the contents of the buffer in a human-readable format */ |
220 | void sshbuf_dump(struct sshbuf *buf, FILE *f); | 220 | void sshbuf_dump(struct sshbuf *buf, FILE *f); |
221 | 221 | ||
222 | /* Dump specified memory in a human-readable format */ | ||
223 | void sshbuf_dump_data(const void *s, size_t len, FILE *f); | ||
224 | |||
222 | /* Return the hexadecimal representation of the contents of the buffer */ | 225 | /* Return the hexadecimal representation of the contents of the buffer */ |
223 | char *sshbuf_dtob16(struct sshbuf *buf); | 226 | char *sshbuf_dtob16(struct sshbuf *buf); |
224 | 227 | ||
diff --git a/sshconnect.c b/sshconnect.c index 5d14ca6cc..590dfe0f7 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect.c,v 1.248 2014/04/29 18:01:49 markus Exp $ */ | 1 | /* $OpenBSD: sshconnect.c,v 1.249 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -709,7 +709,7 @@ check_host_cert(const char *host, const Key *host_key) | |||
709 | error("%s", reason); | 709 | error("%s", reason); |
710 | return 0; | 710 | return 0; |
711 | } | 711 | } |
712 | if (buffer_len(&host_key->cert->critical) != 0) { | 712 | if (buffer_len(host_key->cert->critical) != 0) { |
713 | error("Certificate for %s contains unsupported " | 713 | error("Certificate for %s contains unsupported " |
714 | "critical options(s)", host); | 714 | "critical options(s)", host); |
715 | return 0; | 715 | return 0; |
diff --git a/sshconnect1.c b/sshconnect1.c index 921408ec1..62a7bd17f 100644 --- a/sshconnect1.c +++ b/sshconnect1.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect1.c,v 1.74 2014/02/02 03:44:32 djm Exp $ */ | 1 | /* $OpenBSD: sshconnect1.c,v 1.75 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -166,7 +166,7 @@ respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv) | |||
166 | 166 | ||
167 | /* Decrypt the challenge using the private key. */ | 167 | /* Decrypt the challenge using the private key. */ |
168 | /* XXX think about Bleichenbacher, too */ | 168 | /* XXX think about Bleichenbacher, too */ |
169 | if (rsa_private_decrypt(challenge, challenge, prv) <= 0) | 169 | if (rsa_private_decrypt(challenge, challenge, prv) != 0) |
170 | packet_disconnect( | 170 | packet_disconnect( |
171 | "respond_to_rsa_challenge: rsa_private_decrypt failed"); | 171 | "respond_to_rsa_challenge: rsa_private_decrypt failed"); |
172 | 172 | ||
@@ -253,7 +253,7 @@ try_rsa_authentication(int idx) | |||
253 | * load the private key. Try first with empty passphrase; if it | 253 | * load the private key. Try first with empty passphrase; if it |
254 | * fails, ask for a passphrase. | 254 | * fails, ask for a passphrase. |
255 | */ | 255 | */ |
256 | if (public->flags & KEY_FLAG_EXT) | 256 | if (public->flags & SSHKEY_FLAG_EXT) |
257 | private = public; | 257 | private = public; |
258 | else | 258 | else |
259 | private = key_load_private_type(KEY_RSA1, authfile, "", NULL, | 259 | private = key_load_private_type(KEY_RSA1, authfile, "", NULL, |
@@ -302,7 +302,7 @@ try_rsa_authentication(int idx) | |||
302 | respond_to_rsa_challenge(challenge, private->rsa); | 302 | respond_to_rsa_challenge(challenge, private->rsa); |
303 | 303 | ||
304 | /* Destroy the private key unless it in external hardware. */ | 304 | /* Destroy the private key unless it in external hardware. */ |
305 | if (!(private->flags & KEY_FLAG_EXT)) | 305 | if (!(private->flags & SSHKEY_FLAG_EXT)) |
306 | key_free(private); | 306 | key_free(private); |
307 | 307 | ||
308 | /* We no longer need the challenge. */ | 308 | /* We no longer need the challenge. */ |
@@ -592,8 +592,9 @@ ssh_kex(char *host, struct sockaddr *hostaddr) | |||
592 | BN_num_bits(server_key->rsa->n), | 592 | BN_num_bits(server_key->rsa->n), |
593 | SSH_KEY_BITS_RESERVED); | 593 | SSH_KEY_BITS_RESERVED); |
594 | } | 594 | } |
595 | rsa_public_encrypt(key, key, server_key->rsa); | 595 | if (rsa_public_encrypt(key, key, server_key->rsa) != 0 || |
596 | rsa_public_encrypt(key, key, host_key->rsa); | 596 | rsa_public_encrypt(key, key, host_key->rsa) != 0) |
597 | fatal("%s: rsa_public_encrypt failed", __func__); | ||
597 | } else { | 598 | } else { |
598 | /* Host key has smaller modulus (or they are equal). */ | 599 | /* Host key has smaller modulus (or they are equal). */ |
599 | if (BN_num_bits(server_key->rsa->n) < | 600 | if (BN_num_bits(server_key->rsa->n) < |
@@ -604,8 +605,9 @@ ssh_kex(char *host, struct sockaddr *hostaddr) | |||
604 | BN_num_bits(host_key->rsa->n), | 605 | BN_num_bits(host_key->rsa->n), |
605 | SSH_KEY_BITS_RESERVED); | 606 | SSH_KEY_BITS_RESERVED); |
606 | } | 607 | } |
607 | rsa_public_encrypt(key, key, host_key->rsa); | 608 | if (rsa_public_encrypt(key, key, host_key->rsa) != 0 || |
608 | rsa_public_encrypt(key, key, server_key->rsa); | 609 | rsa_public_encrypt(key, key, server_key->rsa) != 0) |
610 | fatal("%s: rsa_public_encrypt failed", __func__); | ||
609 | } | 611 | } |
610 | 612 | ||
611 | /* Destroy the public keys since we no longer need them. */ | 613 | /* Destroy the public keys since we no longer need them. */ |
diff --git a/sshconnect2.c b/sshconnect2.c index 658398436..eb1b0ae3c 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect2.c,v 1.208 2014/06/05 22:17:50 djm Exp $ */ | 1 | /* $OpenBSD: sshconnect2.c,v 1.209 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2008 Damien Miller. All rights reserved. |
@@ -970,7 +970,7 @@ identity_sign(Identity *id, u_char **sigp, u_int *lenp, | |||
970 | * we have already loaded the private key or | 970 | * we have already loaded the private key or |
971 | * the private key is stored in external hardware | 971 | * the private key is stored in external hardware |
972 | */ | 972 | */ |
973 | if (id->isprivate || (id->key->flags & KEY_FLAG_EXT)) | 973 | if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) |
974 | return (key_sign(id->key, sigp, lenp, data, datalen)); | 974 | return (key_sign(id->key, sigp, lenp, data, datalen)); |
975 | /* load the private key from the file */ | 975 | /* load the private key from the file */ |
976 | if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL) | 976 | if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL) |
@@ -1178,12 +1178,12 @@ pubkey_prepare(Authctxt *authctxt) | |||
1178 | } | 1178 | } |
1179 | /* Prefer PKCS11 keys that are explicitly listed */ | 1179 | /* Prefer PKCS11 keys that are explicitly listed */ |
1180 | TAILQ_FOREACH_SAFE(id, &files, next, tmp) { | 1180 | TAILQ_FOREACH_SAFE(id, &files, next, tmp) { |
1181 | if (id->key == NULL || (id->key->flags & KEY_FLAG_EXT) == 0) | 1181 | if (id->key == NULL || (id->key->flags & SSHKEY_FLAG_EXT) == 0) |
1182 | continue; | 1182 | continue; |
1183 | found = 0; | 1183 | found = 0; |
1184 | TAILQ_FOREACH(id2, &files, next) { | 1184 | TAILQ_FOREACH(id2, &files, next) { |
1185 | if (id2->key == NULL || | 1185 | if (id2->key == NULL || |
1186 | (id2->key->flags & KEY_FLAG_EXT) == 0) | 1186 | (id2->key->flags & SSHKEY_FLAG_EXT) == 0) |
1187 | continue; | 1187 | continue; |
1188 | if (key_equal(id->key, id2->key)) { | 1188 | if (key_equal(id->key, id2->key)) { |
1189 | TAILQ_REMOVE(&files, id, next); | 1189 | TAILQ_REMOVE(&files, id, next); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshd.c,v 1.426 2014/04/29 18:01:49 markus Exp $ */ | 1 | /* $OpenBSD: sshd.c,v 1.427 2014/06/24 01:13:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -1031,8 +1031,10 @@ recv_rexec_state(int fd, Buffer *conf) | |||
1031 | buffer_get_bignum(&m, sensitive_data.server_key->rsa->iqmp); | 1031 | buffer_get_bignum(&m, sensitive_data.server_key->rsa->iqmp); |
1032 | buffer_get_bignum(&m, sensitive_data.server_key->rsa->p); | 1032 | buffer_get_bignum(&m, sensitive_data.server_key->rsa->p); |
1033 | buffer_get_bignum(&m, sensitive_data.server_key->rsa->q); | 1033 | buffer_get_bignum(&m, sensitive_data.server_key->rsa->q); |
1034 | rsa_generate_additional_parameters( | 1034 | if (rsa_generate_additional_parameters( |
1035 | sensitive_data.server_key->rsa); | 1035 | sensitive_data.server_key->rsa) != 0) |
1036 | fatal("%s: rsa_generate_additional_parameters " | ||
1037 | "error", __func__); | ||
1036 | #else | 1038 | #else |
1037 | fatal("ssh1 not supported"); | 1039 | fatal("ssh1 not supported"); |
1038 | #endif | 1040 | #endif |
@@ -2215,10 +2217,10 @@ ssh1_session_key(BIGNUM *session_key_int) | |||
2215 | SSH_KEY_BITS_RESERVED); | 2217 | SSH_KEY_BITS_RESERVED); |
2216 | } | 2218 | } |
2217 | if (rsa_private_decrypt(session_key_int, session_key_int, | 2219 | if (rsa_private_decrypt(session_key_int, session_key_int, |
2218 | sensitive_data.server_key->rsa) <= 0) | 2220 | sensitive_data.server_key->rsa) != 0) |
2219 | rsafail++; | 2221 | rsafail++; |
2220 | if (rsa_private_decrypt(session_key_int, session_key_int, | 2222 | if (rsa_private_decrypt(session_key_int, session_key_int, |
2221 | sensitive_data.ssh1_host_key->rsa) <= 0) | 2223 | sensitive_data.ssh1_host_key->rsa) != 0) |
2222 | rsafail++; | 2224 | rsafail++; |
2223 | } else { | 2225 | } else { |
2224 | /* Host key has bigger modulus (or they are equal). */ | 2226 | /* Host key has bigger modulus (or they are equal). */ |
@@ -2233,10 +2235,10 @@ ssh1_session_key(BIGNUM *session_key_int) | |||
2233 | SSH_KEY_BITS_RESERVED); | 2235 | SSH_KEY_BITS_RESERVED); |
2234 | } | 2236 | } |
2235 | if (rsa_private_decrypt(session_key_int, session_key_int, | 2237 | if (rsa_private_decrypt(session_key_int, session_key_int, |
2236 | sensitive_data.ssh1_host_key->rsa) < 0) | 2238 | sensitive_data.ssh1_host_key->rsa) != 0) |
2237 | rsafail++; | 2239 | rsafail++; |
2238 | if (rsa_private_decrypt(session_key_int, session_key_int, | 2240 | if (rsa_private_decrypt(session_key_int, session_key_int, |
2239 | sensitive_data.server_key->rsa) < 0) | 2241 | sensitive_data.server_key->rsa) != 0) |
2240 | rsafail++; | 2242 | rsafail++; |
2241 | } | 2243 | } |
2242 | return (rsafail); | 2244 | return (rsafail); |
diff --git a/sshkey.c b/sshkey.c new file mode 100644 index 000000000..24023d036 --- /dev/null +++ b/sshkey.c | |||
@@ -0,0 +1,3843 @@ | |||
1 | /* $OpenBSD: sshkey.c,v 1.2 2014/06/27 18:50:39 markus Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | ||
4 | * Copyright (c) 2008 Alexander von Gernler. All rights reserved. | ||
5 | * Copyright (c) 2010,2011 Damien Miller. All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * 2. Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in the | ||
14 | * documentation and/or other materials provided with the distribution. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | #include "includes.h" | ||
29 | |||
30 | #include <sys/param.h> | ||
31 | #include <sys/types.h> | ||
32 | |||
33 | #include <openssl/evp.h> | ||
34 | #include <openssl/err.h> | ||
35 | #include <openssl/pem.h> | ||
36 | |||
37 | #include "crypto_api.h" | ||
38 | |||
39 | #include <errno.h> | ||
40 | #include <stdio.h> | ||
41 | #include <string.h> | ||
42 | #include <util.h> | ||
43 | |||
44 | #include "ssh2.h" | ||
45 | #include "ssherr.h" | ||
46 | #include "misc.h" | ||
47 | #include "sshbuf.h" | ||
48 | #include "rsa.h" | ||
49 | #include "cipher.h" | ||
50 | #include "digest.h" | ||
51 | #define SSHKEY_INTERNAL | ||
52 | #include "sshkey.h" | ||
53 | |||
54 | /* openssh private key file format */ | ||
55 | #define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" | ||
56 | #define MARK_END "-----END OPENSSH PRIVATE KEY-----\n" | ||
57 | #define MARK_BEGIN_LEN (sizeof(MARK_BEGIN) - 1) | ||
58 | #define MARK_END_LEN (sizeof(MARK_END) - 1) | ||
59 | #define KDFNAME "bcrypt" | ||
60 | #define AUTH_MAGIC "openssh-key-v1" | ||
61 | #define SALT_LEN 16 | ||
62 | #define DEFAULT_CIPHERNAME "aes256-cbc" | ||
63 | #define DEFAULT_ROUNDS 16 | ||
64 | |||
65 | /* Version identification string for SSH v1 identity files. */ | ||
66 | #define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n" | ||
67 | |||
68 | static int sshkey_from_blob_internal(const u_char *blob, size_t blen, | ||
69 | struct sshkey **keyp, int allow_cert); | ||
70 | |||
71 | /* Supported key types */ | ||
72 | struct keytype { | ||
73 | const char *name; | ||
74 | const char *shortname; | ||
75 | int type; | ||
76 | int nid; | ||
77 | int cert; | ||
78 | }; | ||
79 | static const struct keytype keytypes[] = { | ||
80 | { "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0 }, | ||
81 | { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", | ||
82 | KEY_ED25519_CERT, 0, 1 }, | ||
83 | #ifdef WITH_OPENSSL | ||
84 | { NULL, "RSA1", KEY_RSA1, 0, 0 }, | ||
85 | { "ssh-rsa", "RSA", KEY_RSA, 0, 0 }, | ||
86 | { "ssh-dss", "DSA", KEY_DSA, 0, 0 }, | ||
87 | # ifdef OPENSSL_HAS_ECC | ||
88 | { "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0 }, | ||
89 | { "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0 }, | ||
90 | # ifdef OPENSSL_HAS_NISTP521 | ||
91 | { "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0 }, | ||
92 | # endif /* OPENSSL_HAS_NISTP521 */ | ||
93 | # endif /* OPENSSL_HAS_ECC */ | ||
94 | { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", KEY_RSA_CERT, 0, 1 }, | ||
95 | { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", KEY_DSA_CERT, 0, 1 }, | ||
96 | # ifdef OPENSSL_HAS_ECC | ||
97 | { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT", | ||
98 | KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1 }, | ||
99 | { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT", | ||
100 | KEY_ECDSA_CERT, NID_secp384r1, 1 }, | ||
101 | # ifdef OPENSSL_HAS_NISTP521 | ||
102 | { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT", | ||
103 | KEY_ECDSA_CERT, NID_secp521r1, 1 }, | ||
104 | # endif /* OPENSSL_HAS_NISTP521 */ | ||
105 | # endif /* OPENSSL_HAS_ECC */ | ||
106 | { "ssh-rsa-cert-v00@openssh.com", "RSA-CERT-V00", | ||
107 | KEY_RSA_CERT_V00, 0, 1 }, | ||
108 | { "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00", | ||
109 | KEY_DSA_CERT_V00, 0, 1 }, | ||
110 | #endif /* WITH_OPENSSL */ | ||
111 | { NULL, NULL, -1, -1, 0 } | ||
112 | }; | ||
113 | |||
114 | const char * | ||
115 | sshkey_type(const struct sshkey *k) | ||
116 | { | ||
117 | const struct keytype *kt; | ||
118 | |||
119 | for (kt = keytypes; kt->type != -1; kt++) { | ||
120 | if (kt->type == k->type) | ||
121 | return kt->shortname; | ||
122 | } | ||
123 | return "unknown"; | ||
124 | } | ||
125 | |||
126 | static const char * | ||
127 | sshkey_ssh_name_from_type_nid(int type, int nid) | ||
128 | { | ||
129 | const struct keytype *kt; | ||
130 | |||
131 | for (kt = keytypes; kt->type != -1; kt++) { | ||
132 | if (kt->type == type && (kt->nid == 0 || kt->nid == nid)) | ||
133 | return kt->name; | ||
134 | } | ||
135 | return "ssh-unknown"; | ||
136 | } | ||
137 | |||
138 | int | ||
139 | sshkey_type_is_cert(int type) | ||
140 | { | ||
141 | const struct keytype *kt; | ||
142 | |||
143 | for (kt = keytypes; kt->type != -1; kt++) { | ||
144 | if (kt->type == type) | ||
145 | return kt->cert; | ||
146 | } | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | const char * | ||
151 | sshkey_ssh_name(const struct sshkey *k) | ||
152 | { | ||
153 | return sshkey_ssh_name_from_type_nid(k->type, k->ecdsa_nid); | ||
154 | } | ||
155 | |||
156 | const char * | ||
157 | sshkey_ssh_name_plain(const struct sshkey *k) | ||
158 | { | ||
159 | return sshkey_ssh_name_from_type_nid(sshkey_type_plain(k->type), | ||
160 | k->ecdsa_nid); | ||
161 | } | ||
162 | |||
163 | int | ||
164 | sshkey_type_from_name(const char *name) | ||
165 | { | ||
166 | const struct keytype *kt; | ||
167 | |||
168 | for (kt = keytypes; kt->type != -1; kt++) { | ||
169 | /* Only allow shortname matches for plain key types */ | ||
170 | if ((kt->name != NULL && strcmp(name, kt->name) == 0) || | ||
171 | (!kt->cert && strcasecmp(kt->shortname, name) == 0)) | ||
172 | return kt->type; | ||
173 | } | ||
174 | return KEY_UNSPEC; | ||
175 | } | ||
176 | |||
177 | int | ||
178 | sshkey_ecdsa_nid_from_name(const char *name) | ||
179 | { | ||
180 | const struct keytype *kt; | ||
181 | |||
182 | for (kt = keytypes; kt->type != -1; kt++) { | ||
183 | if (kt->type != KEY_ECDSA && kt->type != KEY_ECDSA_CERT) | ||
184 | continue; | ||
185 | if (kt->name != NULL && strcmp(name, kt->name) == 0) | ||
186 | return kt->nid; | ||
187 | } | ||
188 | return -1; | ||
189 | } | ||
190 | |||
191 | char * | ||
192 | key_alg_list(int certs_only, int plain_only) | ||
193 | { | ||
194 | char *tmp, *ret = NULL; | ||
195 | size_t nlen, rlen = 0; | ||
196 | const struct keytype *kt; | ||
197 | |||
198 | for (kt = keytypes; kt->type != -1; kt++) { | ||
199 | if (kt->name == NULL) | ||
200 | continue; | ||
201 | if ((certs_only && !kt->cert) || (plain_only && kt->cert)) | ||
202 | continue; | ||
203 | if (ret != NULL) | ||
204 | ret[rlen++] = '\n'; | ||
205 | nlen = strlen(kt->name); | ||
206 | if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { | ||
207 | free(ret); | ||
208 | return NULL; | ||
209 | } | ||
210 | ret = tmp; | ||
211 | memcpy(ret + rlen, kt->name, nlen + 1); | ||
212 | rlen += nlen; | ||
213 | } | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | int | ||
218 | sshkey_names_valid2(const char *names) | ||
219 | { | ||
220 | char *s, *cp, *p; | ||
221 | |||
222 | if (names == NULL || strcmp(names, "") == 0) | ||
223 | return 0; | ||
224 | if ((s = cp = strdup(names)) == NULL) | ||
225 | return 0; | ||
226 | for ((p = strsep(&cp, ",")); p && *p != '\0'; | ||
227 | (p = strsep(&cp, ","))) { | ||
228 | switch (sshkey_type_from_name(p)) { | ||
229 | case KEY_RSA1: | ||
230 | case KEY_UNSPEC: | ||
231 | free(s); | ||
232 | return 0; | ||
233 | } | ||
234 | } | ||
235 | free(s); | ||
236 | return 1; | ||
237 | } | ||
238 | |||
239 | u_int | ||
240 | sshkey_size(const struct sshkey *k) | ||
241 | { | ||
242 | switch (k->type) { | ||
243 | #ifdef WITH_OPENSSL | ||
244 | case KEY_RSA1: | ||
245 | case KEY_RSA: | ||
246 | case KEY_RSA_CERT_V00: | ||
247 | case KEY_RSA_CERT: | ||
248 | return BN_num_bits(k->rsa->n); | ||
249 | case KEY_DSA: | ||
250 | case KEY_DSA_CERT_V00: | ||
251 | case KEY_DSA_CERT: | ||
252 | return BN_num_bits(k->dsa->p); | ||
253 | case KEY_ECDSA: | ||
254 | case KEY_ECDSA_CERT: | ||
255 | return sshkey_curve_nid_to_bits(k->ecdsa_nid); | ||
256 | #endif /* WITH_OPENSSL */ | ||
257 | case KEY_ED25519: | ||
258 | case KEY_ED25519_CERT: | ||
259 | return 256; /* XXX */ | ||
260 | } | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | int | ||
265 | sshkey_cert_is_legacy(const struct sshkey *k) | ||
266 | { | ||
267 | switch (k->type) { | ||
268 | case KEY_DSA_CERT_V00: | ||
269 | case KEY_RSA_CERT_V00: | ||
270 | return 1; | ||
271 | default: | ||
272 | return 0; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | static int | ||
277 | sshkey_type_is_valid_ca(int type) | ||
278 | { | ||
279 | switch (type) { | ||
280 | case KEY_RSA: | ||
281 | case KEY_DSA: | ||
282 | case KEY_ECDSA: | ||
283 | case KEY_ED25519: | ||
284 | return 1; | ||
285 | default: | ||
286 | return 0; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | int | ||
291 | sshkey_is_cert(const struct sshkey *k) | ||
292 | { | ||
293 | if (k == NULL) | ||
294 | return 0; | ||
295 | return sshkey_type_is_cert(k->type); | ||
296 | } | ||
297 | |||
298 | /* Return the cert-less equivalent to a certified key type */ | ||
299 | int | ||
300 | sshkey_type_plain(int type) | ||
301 | { | ||
302 | switch (type) { | ||
303 | case KEY_RSA_CERT_V00: | ||
304 | case KEY_RSA_CERT: | ||
305 | return KEY_RSA; | ||
306 | case KEY_DSA_CERT_V00: | ||
307 | case KEY_DSA_CERT: | ||
308 | return KEY_DSA; | ||
309 | case KEY_ECDSA_CERT: | ||
310 | return KEY_ECDSA; | ||
311 | case KEY_ED25519_CERT: | ||
312 | return KEY_ED25519; | ||
313 | default: | ||
314 | return type; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | #ifdef WITH_OPENSSL | ||
319 | /* XXX: these are really begging for a table-driven approach */ | ||
320 | int | ||
321 | sshkey_curve_name_to_nid(const char *name) | ||
322 | { | ||
323 | if (strcmp(name, "nistp256") == 0) | ||
324 | return NID_X9_62_prime256v1; | ||
325 | else if (strcmp(name, "nistp384") == 0) | ||
326 | return NID_secp384r1; | ||
327 | # ifdef OPENSSL_HAS_NISTP521 | ||
328 | else if (strcmp(name, "nistp521") == 0) | ||
329 | return NID_secp521r1; | ||
330 | # endif /* OPENSSL_HAS_NISTP521 */ | ||
331 | else | ||
332 | return -1; | ||
333 | } | ||
334 | |||
335 | u_int | ||
336 | sshkey_curve_nid_to_bits(int nid) | ||
337 | { | ||
338 | switch (nid) { | ||
339 | case NID_X9_62_prime256v1: | ||
340 | return 256; | ||
341 | case NID_secp384r1: | ||
342 | return 384; | ||
343 | # ifdef OPENSSL_HAS_NISTP521 | ||
344 | case NID_secp521r1: | ||
345 | return 521; | ||
346 | # endif /* OPENSSL_HAS_NISTP521 */ | ||
347 | default: | ||
348 | return 0; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | int | ||
353 | sshkey_ecdsa_bits_to_nid(int bits) | ||
354 | { | ||
355 | switch (bits) { | ||
356 | case 256: | ||
357 | return NID_X9_62_prime256v1; | ||
358 | case 384: | ||
359 | return NID_secp384r1; | ||
360 | # ifdef OPENSSL_HAS_NISTP521 | ||
361 | case 521: | ||
362 | return NID_secp521r1; | ||
363 | # endif /* OPENSSL_HAS_NISTP521 */ | ||
364 | default: | ||
365 | return -1; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | const char * | ||
370 | sshkey_curve_nid_to_name(int nid) | ||
371 | { | ||
372 | switch (nid) { | ||
373 | case NID_X9_62_prime256v1: | ||
374 | return "nistp256"; | ||
375 | case NID_secp384r1: | ||
376 | return "nistp384"; | ||
377 | # ifdef OPENSSL_HAS_NISTP521 | ||
378 | case NID_secp521r1: | ||
379 | return "nistp521"; | ||
380 | # endif /* OPENSSL_HAS_NISTP521 */ | ||
381 | default: | ||
382 | return NULL; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | int | ||
387 | sshkey_ec_nid_to_hash_alg(int nid) | ||
388 | { | ||
389 | int kbits = sshkey_curve_nid_to_bits(nid); | ||
390 | |||
391 | if (kbits <= 0) | ||
392 | return -1; | ||
393 | |||
394 | /* RFC5656 section 6.2.1 */ | ||
395 | if (kbits <= 256) | ||
396 | return SSH_DIGEST_SHA256; | ||
397 | else if (kbits <= 384) | ||
398 | return SSH_DIGEST_SHA384; | ||
399 | else | ||
400 | return SSH_DIGEST_SHA512; | ||
401 | } | ||
402 | #endif /* WITH_OPENSSL */ | ||
403 | |||
404 | static void | ||
405 | cert_free(struct sshkey_cert *cert) | ||
406 | { | ||
407 | u_int i; | ||
408 | |||
409 | if (cert == NULL) | ||
410 | return; | ||
411 | if (cert->certblob != NULL) | ||
412 | sshbuf_free(cert->certblob); | ||
413 | if (cert->critical != NULL) | ||
414 | sshbuf_free(cert->critical); | ||
415 | if (cert->extensions != NULL) | ||
416 | sshbuf_free(cert->extensions); | ||
417 | if (cert->key_id != NULL) | ||
418 | free(cert->key_id); | ||
419 | for (i = 0; i < cert->nprincipals; i++) | ||
420 | free(cert->principals[i]); | ||
421 | if (cert->principals != NULL) | ||
422 | free(cert->principals); | ||
423 | if (cert->signature_key != NULL) | ||
424 | sshkey_free(cert->signature_key); | ||
425 | explicit_bzero(cert, sizeof(*cert)); | ||
426 | free(cert); | ||
427 | } | ||
428 | |||
429 | static struct sshkey_cert * | ||
430 | cert_new(void) | ||
431 | { | ||
432 | struct sshkey_cert *cert; | ||
433 | |||
434 | if ((cert = calloc(1, sizeof(*cert))) == NULL) | ||
435 | return NULL; | ||
436 | if ((cert->certblob = sshbuf_new()) == NULL || | ||
437 | (cert->critical = sshbuf_new()) == NULL || | ||
438 | (cert->extensions = sshbuf_new()) == NULL) { | ||
439 | cert_free(cert); | ||
440 | return NULL; | ||
441 | } | ||
442 | cert->key_id = NULL; | ||
443 | cert->principals = NULL; | ||
444 | cert->signature_key = NULL; | ||
445 | return cert; | ||
446 | } | ||
447 | |||
448 | struct sshkey * | ||
449 | sshkey_new(int type) | ||
450 | { | ||
451 | struct sshkey *k; | ||
452 | #ifdef WITH_OPENSSL | ||
453 | RSA *rsa; | ||
454 | DSA *dsa; | ||
455 | #endif /* WITH_OPENSSL */ | ||
456 | |||
457 | if ((k = calloc(1, sizeof(*k))) == NULL) | ||
458 | return NULL; | ||
459 | k->type = type; | ||
460 | k->ecdsa = NULL; | ||
461 | k->ecdsa_nid = -1; | ||
462 | k->dsa = NULL; | ||
463 | k->rsa = NULL; | ||
464 | k->cert = NULL; | ||
465 | k->ed25519_sk = NULL; | ||
466 | k->ed25519_pk = NULL; | ||
467 | switch (k->type) { | ||
468 | #ifdef WITH_OPENSSL | ||
469 | case KEY_RSA1: | ||
470 | case KEY_RSA: | ||
471 | case KEY_RSA_CERT_V00: | ||
472 | case KEY_RSA_CERT: | ||
473 | if ((rsa = RSA_new()) == NULL || | ||
474 | (rsa->n = BN_new()) == NULL || | ||
475 | (rsa->e = BN_new()) == NULL) { | ||
476 | if (rsa != NULL) | ||
477 | RSA_free(rsa); | ||
478 | free(k); | ||
479 | return NULL; | ||
480 | } | ||
481 | k->rsa = rsa; | ||
482 | break; | ||
483 | case KEY_DSA: | ||
484 | case KEY_DSA_CERT_V00: | ||
485 | case KEY_DSA_CERT: | ||
486 | if ((dsa = DSA_new()) == NULL || | ||
487 | (dsa->p = BN_new()) == NULL || | ||
488 | (dsa->q = BN_new()) == NULL || | ||
489 | (dsa->g = BN_new()) == NULL || | ||
490 | (dsa->pub_key = BN_new()) == NULL) { | ||
491 | if (dsa != NULL) | ||
492 | DSA_free(dsa); | ||
493 | free(k); | ||
494 | return NULL; | ||
495 | } | ||
496 | k->dsa = dsa; | ||
497 | break; | ||
498 | case KEY_ECDSA: | ||
499 | case KEY_ECDSA_CERT: | ||
500 | /* Cannot do anything until we know the group */ | ||
501 | break; | ||
502 | #endif /* WITH_OPENSSL */ | ||
503 | case KEY_ED25519: | ||
504 | case KEY_ED25519_CERT: | ||
505 | /* no need to prealloc */ | ||
506 | break; | ||
507 | case KEY_UNSPEC: | ||
508 | break; | ||
509 | default: | ||
510 | free(k); | ||
511 | return NULL; | ||
512 | break; | ||
513 | } | ||
514 | |||
515 | if (sshkey_is_cert(k)) { | ||
516 | if ((k->cert = cert_new()) == NULL) { | ||
517 | sshkey_free(k); | ||
518 | return NULL; | ||
519 | } | ||
520 | } | ||
521 | |||
522 | return k; | ||
523 | } | ||
524 | |||
525 | int | ||
526 | sshkey_add_private(struct sshkey *k) | ||
527 | { | ||
528 | switch (k->type) { | ||
529 | #ifdef WITH_OPENSSL | ||
530 | case KEY_RSA1: | ||
531 | case KEY_RSA: | ||
532 | case KEY_RSA_CERT_V00: | ||
533 | case KEY_RSA_CERT: | ||
534 | #define bn_maybe_alloc_failed(p) (p == NULL && (p = BN_new()) == NULL) | ||
535 | if (bn_maybe_alloc_failed(k->rsa->d) || | ||
536 | bn_maybe_alloc_failed(k->rsa->iqmp) || | ||
537 | bn_maybe_alloc_failed(k->rsa->q) || | ||
538 | bn_maybe_alloc_failed(k->rsa->p) || | ||
539 | bn_maybe_alloc_failed(k->rsa->dmq1) || | ||
540 | bn_maybe_alloc_failed(k->rsa->dmp1)) | ||
541 | return SSH_ERR_ALLOC_FAIL; | ||
542 | break; | ||
543 | case KEY_DSA: | ||
544 | case KEY_DSA_CERT_V00: | ||
545 | case KEY_DSA_CERT: | ||
546 | if (bn_maybe_alloc_failed(k->dsa->priv_key)) | ||
547 | return SSH_ERR_ALLOC_FAIL; | ||
548 | break; | ||
549 | #undef bn_maybe_alloc_failed | ||
550 | case KEY_ECDSA: | ||
551 | case KEY_ECDSA_CERT: | ||
552 | /* Cannot do anything until we know the group */ | ||
553 | break; | ||
554 | #endif /* WITH_OPENSSL */ | ||
555 | case KEY_ED25519: | ||
556 | case KEY_ED25519_CERT: | ||
557 | /* no need to prealloc */ | ||
558 | break; | ||
559 | case KEY_UNSPEC: | ||
560 | break; | ||
561 | default: | ||
562 | return SSH_ERR_INVALID_ARGUMENT; | ||
563 | } | ||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | struct sshkey * | ||
568 | sshkey_new_private(int type) | ||
569 | { | ||
570 | struct sshkey *k = sshkey_new(type); | ||
571 | |||
572 | if (k == NULL) | ||
573 | return NULL; | ||
574 | if (sshkey_add_private(k) != 0) { | ||
575 | sshkey_free(k); | ||
576 | return NULL; | ||
577 | } | ||
578 | return k; | ||
579 | } | ||
580 | |||
581 | void | ||
582 | sshkey_free(struct sshkey *k) | ||
583 | { | ||
584 | if (k == NULL) | ||
585 | return; | ||
586 | switch (k->type) { | ||
587 | #ifdef WITH_OPENSSL | ||
588 | case KEY_RSA1: | ||
589 | case KEY_RSA: | ||
590 | case KEY_RSA_CERT_V00: | ||
591 | case KEY_RSA_CERT: | ||
592 | if (k->rsa != NULL) | ||
593 | RSA_free(k->rsa); | ||
594 | k->rsa = NULL; | ||
595 | break; | ||
596 | case KEY_DSA: | ||
597 | case KEY_DSA_CERT_V00: | ||
598 | case KEY_DSA_CERT: | ||
599 | if (k->dsa != NULL) | ||
600 | DSA_free(k->dsa); | ||
601 | k->dsa = NULL; | ||
602 | break; | ||
603 | # ifdef OPENSSL_HAS_ECC | ||
604 | case KEY_ECDSA: | ||
605 | case KEY_ECDSA_CERT: | ||
606 | if (k->ecdsa != NULL) | ||
607 | EC_KEY_free(k->ecdsa); | ||
608 | k->ecdsa = NULL; | ||
609 | break; | ||
610 | # endif /* OPENSSL_HAS_ECC */ | ||
611 | #endif /* WITH_OPENSSL */ | ||
612 | case KEY_ED25519: | ||
613 | case KEY_ED25519_CERT: | ||
614 | if (k->ed25519_pk) { | ||
615 | explicit_bzero(k->ed25519_pk, ED25519_PK_SZ); | ||
616 | free(k->ed25519_pk); | ||
617 | k->ed25519_pk = NULL; | ||
618 | } | ||
619 | if (k->ed25519_sk) { | ||
620 | explicit_bzero(k->ed25519_sk, ED25519_SK_SZ); | ||
621 | free(k->ed25519_sk); | ||
622 | k->ed25519_sk = NULL; | ||
623 | } | ||
624 | break; | ||
625 | case KEY_UNSPEC: | ||
626 | break; | ||
627 | default: | ||
628 | break; | ||
629 | } | ||
630 | if (sshkey_is_cert(k)) | ||
631 | cert_free(k->cert); | ||
632 | explicit_bzero(k, sizeof(*k)); | ||
633 | free(k); | ||
634 | } | ||
635 | |||
636 | static int | ||
637 | cert_compare(struct sshkey_cert *a, struct sshkey_cert *b) | ||
638 | { | ||
639 | if (a == NULL && b == NULL) | ||
640 | return 1; | ||
641 | if (a == NULL || b == NULL) | ||
642 | return 0; | ||
643 | if (sshbuf_len(a->certblob) != sshbuf_len(b->certblob)) | ||
644 | return 0; | ||
645 | if (timingsafe_bcmp(sshbuf_ptr(a->certblob), sshbuf_ptr(b->certblob), | ||
646 | sshbuf_len(a->certblob)) != 0) | ||
647 | return 0; | ||
648 | return 1; | ||
649 | } | ||
650 | |||
651 | /* | ||
652 | * Compare public portions of key only, allowing comparisons between | ||
653 | * certificates and plain keys too. | ||
654 | */ | ||
655 | int | ||
656 | sshkey_equal_public(const struct sshkey *a, const struct sshkey *b) | ||
657 | { | ||
658 | #ifdef WITH_OPENSSL | ||
659 | BN_CTX *bnctx; | ||
660 | #endif /* WITH_OPENSSL */ | ||
661 | |||
662 | if (a == NULL || b == NULL || | ||
663 | sshkey_type_plain(a->type) != sshkey_type_plain(b->type)) | ||
664 | return 0; | ||
665 | |||
666 | switch (a->type) { | ||
667 | #ifdef WITH_OPENSSL | ||
668 | case KEY_RSA1: | ||
669 | case KEY_RSA_CERT_V00: | ||
670 | case KEY_RSA_CERT: | ||
671 | case KEY_RSA: | ||
672 | return a->rsa != NULL && b->rsa != NULL && | ||
673 | BN_cmp(a->rsa->e, b->rsa->e) == 0 && | ||
674 | BN_cmp(a->rsa->n, b->rsa->n) == 0; | ||
675 | case KEY_DSA_CERT_V00: | ||
676 | case KEY_DSA_CERT: | ||
677 | case KEY_DSA: | ||
678 | return a->dsa != NULL && b->dsa != NULL && | ||
679 | BN_cmp(a->dsa->p, b->dsa->p) == 0 && | ||
680 | BN_cmp(a->dsa->q, b->dsa->q) == 0 && | ||
681 | BN_cmp(a->dsa->g, b->dsa->g) == 0 && | ||
682 | BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0; | ||
683 | # ifdef OPENSSL_HAS_ECC | ||
684 | case KEY_ECDSA_CERT: | ||
685 | case KEY_ECDSA: | ||
686 | if (a->ecdsa == NULL || b->ecdsa == NULL || | ||
687 | EC_KEY_get0_public_key(a->ecdsa) == NULL || | ||
688 | EC_KEY_get0_public_key(b->ecdsa) == NULL) | ||
689 | return 0; | ||
690 | if ((bnctx = BN_CTX_new()) == NULL) | ||
691 | return 0; | ||
692 | if (EC_GROUP_cmp(EC_KEY_get0_group(a->ecdsa), | ||
693 | EC_KEY_get0_group(b->ecdsa), bnctx) != 0 || | ||
694 | EC_POINT_cmp(EC_KEY_get0_group(a->ecdsa), | ||
695 | EC_KEY_get0_public_key(a->ecdsa), | ||
696 | EC_KEY_get0_public_key(b->ecdsa), bnctx) != 0) { | ||
697 | BN_CTX_free(bnctx); | ||
698 | return 0; | ||
699 | } | ||
700 | BN_CTX_free(bnctx); | ||
701 | return 1; | ||
702 | # endif /* OPENSSL_HAS_ECC */ | ||
703 | #endif /* WITH_OPENSSL */ | ||
704 | case KEY_ED25519: | ||
705 | case KEY_ED25519_CERT: | ||
706 | return a->ed25519_pk != NULL && b->ed25519_pk != NULL && | ||
707 | memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0; | ||
708 | default: | ||
709 | return 0; | ||
710 | } | ||
711 | /* NOTREACHED */ | ||
712 | } | ||
713 | |||
714 | int | ||
715 | sshkey_equal(const struct sshkey *a, const struct sshkey *b) | ||
716 | { | ||
717 | if (a == NULL || b == NULL || a->type != b->type) | ||
718 | return 0; | ||
719 | if (sshkey_is_cert(a)) { | ||
720 | if (!cert_compare(a->cert, b->cert)) | ||
721 | return 0; | ||
722 | } | ||
723 | return sshkey_equal_public(a, b); | ||
724 | } | ||
725 | |||
726 | static int | ||
727 | to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain) | ||
728 | { | ||
729 | int type, ret = SSH_ERR_INTERNAL_ERROR; | ||
730 | const char *typename; | ||
731 | |||
732 | if (key == NULL) | ||
733 | return SSH_ERR_INVALID_ARGUMENT; | ||
734 | |||
735 | type = force_plain ? sshkey_type_plain(key->type) : key->type; | ||
736 | typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid); | ||
737 | |||
738 | switch (type) { | ||
739 | #ifdef WITH_OPENSSL | ||
740 | case KEY_DSA_CERT_V00: | ||
741 | case KEY_RSA_CERT_V00: | ||
742 | case KEY_DSA_CERT: | ||
743 | case KEY_ECDSA_CERT: | ||
744 | case KEY_RSA_CERT: | ||
745 | #endif /* WITH_OPENSSL */ | ||
746 | case KEY_ED25519_CERT: | ||
747 | /* Use the existing blob */ | ||
748 | /* XXX modified flag? */ | ||
749 | if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0) | ||
750 | return ret; | ||
751 | break; | ||
752 | #ifdef WITH_OPENSSL | ||
753 | case KEY_DSA: | ||
754 | if (key->dsa == NULL) | ||
755 | return SSH_ERR_INVALID_ARGUMENT; | ||
756 | if ((ret = sshbuf_put_cstring(b, typename)) != 0 || | ||
757 | (ret = sshbuf_put_bignum2(b, key->dsa->p)) != 0 || | ||
758 | (ret = sshbuf_put_bignum2(b, key->dsa->q)) != 0 || | ||
759 | (ret = sshbuf_put_bignum2(b, key->dsa->g)) != 0 || | ||
760 | (ret = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0) | ||
761 | return ret; | ||
762 | break; | ||
763 | case KEY_ECDSA: | ||
764 | if (key->ecdsa == NULL) | ||
765 | return SSH_ERR_INVALID_ARGUMENT; | ||
766 | if ((ret = sshbuf_put_cstring(b, typename)) != 0 || | ||
767 | (ret = sshbuf_put_cstring(b, | ||
768 | sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || | ||
769 | (ret = sshbuf_put_eckey(b, key->ecdsa)) != 0) | ||
770 | return ret; | ||
771 | break; | ||
772 | case KEY_RSA: | ||
773 | if (key->rsa == NULL) | ||
774 | return SSH_ERR_INVALID_ARGUMENT; | ||
775 | if ((ret = sshbuf_put_cstring(b, typename)) != 0 || | ||
776 | (ret = sshbuf_put_bignum2(b, key->rsa->e)) != 0 || | ||
777 | (ret = sshbuf_put_bignum2(b, key->rsa->n)) != 0) | ||
778 | return ret; | ||
779 | break; | ||
780 | #endif /* WITH_OPENSSL */ | ||
781 | case KEY_ED25519: | ||
782 | if (key->ed25519_pk == NULL) | ||
783 | return SSH_ERR_INVALID_ARGUMENT; | ||
784 | if ((ret = sshbuf_put_cstring(b, typename)) != 0 || | ||
785 | (ret = sshbuf_put_string(b, | ||
786 | key->ed25519_pk, ED25519_PK_SZ)) != 0) | ||
787 | return ret; | ||
788 | break; | ||
789 | default: | ||
790 | return SSH_ERR_KEY_TYPE_UNKNOWN; | ||
791 | } | ||
792 | return 0; | ||
793 | } | ||
794 | |||
795 | int | ||
796 | sshkey_to_blob_buf(const struct sshkey *key, struct sshbuf *b) | ||
797 | { | ||
798 | return to_blob_buf(key, b, 0); | ||
799 | } | ||
800 | |||
801 | int | ||
802 | sshkey_plain_to_blob_buf(const struct sshkey *key, struct sshbuf *b) | ||
803 | { | ||
804 | return to_blob_buf(key, b, 1); | ||
805 | } | ||
806 | |||
807 | static int | ||
808 | to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain) | ||
809 | { | ||
810 | int ret = SSH_ERR_INTERNAL_ERROR; | ||
811 | size_t len; | ||
812 | struct sshbuf *b = NULL; | ||
813 | |||
814 | if (lenp != NULL) | ||
815 | *lenp = 0; | ||
816 | if (blobp != NULL) | ||
817 | *blobp = NULL; | ||
818 | if ((b = sshbuf_new()) == NULL) | ||
819 | return SSH_ERR_ALLOC_FAIL; | ||
820 | if ((ret = to_blob_buf(key, b, force_plain)) != 0) | ||
821 | goto out; | ||
822 | len = sshbuf_len(b); | ||
823 | if (lenp != NULL) | ||
824 | *lenp = len; | ||
825 | if (blobp != NULL) { | ||
826 | if ((*blobp = malloc(len)) == NULL) { | ||
827 | ret = SSH_ERR_ALLOC_FAIL; | ||
828 | goto out; | ||
829 | } | ||
830 | memcpy(*blobp, sshbuf_ptr(b), len); | ||
831 | } | ||
832 | ret = 0; | ||
833 | out: | ||
834 | sshbuf_free(b); | ||
835 | return ret; | ||
836 | } | ||
837 | |||
838 | int | ||
839 | sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp) | ||
840 | { | ||
841 | return to_blob(key, blobp, lenp, 0); | ||
842 | } | ||
843 | |||
844 | int | ||
845 | sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp) | ||
846 | { | ||
847 | return to_blob(key, blobp, lenp, 1); | ||
848 | } | ||
849 | |||
850 | int | ||
851 | sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type, | ||
852 | u_char **retp, size_t *lenp) | ||
853 | { | ||
854 | u_char *blob = NULL, *ret = NULL; | ||
855 | size_t blob_len = 0; | ||
856 | int hash_alg = -1, r = SSH_ERR_INTERNAL_ERROR; | ||
857 | |||
858 | if (retp != NULL) | ||
859 | *retp = NULL; | ||
860 | if (lenp != NULL) | ||
861 | *lenp = 0; | ||
862 | |||
863 | switch (dgst_type) { | ||
864 | case SSH_FP_MD5: | ||
865 | hash_alg = SSH_DIGEST_MD5; | ||
866 | break; | ||
867 | case SSH_FP_SHA1: | ||
868 | hash_alg = SSH_DIGEST_SHA1; | ||
869 | break; | ||
870 | case SSH_FP_SHA256: | ||
871 | hash_alg = SSH_DIGEST_SHA256; | ||
872 | break; | ||
873 | default: | ||
874 | r = SSH_ERR_INVALID_ARGUMENT; | ||
875 | goto out; | ||
876 | } | ||
877 | |||
878 | if (k->type == KEY_RSA1) { | ||
879 | #ifdef WITH_OPENSSL | ||
880 | int nlen = BN_num_bytes(k->rsa->n); | ||
881 | int elen = BN_num_bytes(k->rsa->e); | ||
882 | |||
883 | blob_len = nlen + elen; | ||
884 | if (nlen >= INT_MAX - elen || | ||
885 | (blob = malloc(blob_len)) == NULL) { | ||
886 | r = SSH_ERR_ALLOC_FAIL; | ||
887 | goto out; | ||
888 | } | ||
889 | BN_bn2bin(k->rsa->n, blob); | ||
890 | BN_bn2bin(k->rsa->e, blob + nlen); | ||
891 | #endif /* WITH_OPENSSL */ | ||
892 | } else if ((r = to_blob(k, &blob, &blob_len, 1)) != 0) | ||
893 | goto out; | ||
894 | if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) { | ||
895 | r = SSH_ERR_ALLOC_FAIL; | ||
896 | goto out; | ||
897 | } | ||
898 | if ((r = ssh_digest_memory(hash_alg, blob, blob_len, | ||
899 | ret, SSH_DIGEST_MAX_LENGTH)) != 0) | ||
900 | goto out; | ||
901 | /* success */ | ||
902 | if (retp != NULL) { | ||
903 | *retp = ret; | ||
904 | ret = NULL; | ||
905 | } | ||
906 | if (lenp != NULL) | ||
907 | *lenp = ssh_digest_bytes(hash_alg); | ||
908 | r = 0; | ||
909 | out: | ||
910 | free(ret); | ||
911 | if (blob != NULL) { | ||
912 | explicit_bzero(blob, blob_len); | ||
913 | free(blob); | ||
914 | } | ||
915 | return r; | ||
916 | } | ||
917 | |||
918 | static char * | ||
919 | fingerprint_hex(u_char *dgst_raw, size_t dgst_raw_len) | ||
920 | { | ||
921 | char *retval; | ||
922 | size_t i; | ||
923 | |||
924 | if ((retval = calloc(1, dgst_raw_len * 3 + 1)) == NULL) | ||
925 | return NULL; | ||
926 | for (i = 0; i < dgst_raw_len; i++) { | ||
927 | char hex[4]; | ||
928 | snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]); | ||
929 | strlcat(retval, hex, dgst_raw_len * 3 + 1); | ||
930 | } | ||
931 | |||
932 | /* Remove the trailing ':' character */ | ||
933 | retval[(dgst_raw_len * 3) - 1] = '\0'; | ||
934 | return retval; | ||
935 | } | ||
936 | |||
937 | static char * | ||
938 | fingerprint_bubblebabble(u_char *dgst_raw, size_t dgst_raw_len) | ||
939 | { | ||
940 | char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; | ||
941 | char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', | ||
942 | 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' }; | ||
943 | u_int i, j = 0, rounds, seed = 1; | ||
944 | char *retval; | ||
945 | |||
946 | rounds = (dgst_raw_len / 2) + 1; | ||
947 | if ((retval = calloc(rounds, 6)) == NULL) | ||
948 | return NULL; | ||
949 | retval[j++] = 'x'; | ||
950 | for (i = 0; i < rounds; i++) { | ||
951 | u_int idx0, idx1, idx2, idx3, idx4; | ||
952 | if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) { | ||
953 | idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) + | ||
954 | seed) % 6; | ||
955 | idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15; | ||
956 | idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) + | ||
957 | (seed / 6)) % 6; | ||
958 | retval[j++] = vowels[idx0]; | ||
959 | retval[j++] = consonants[idx1]; | ||
960 | retval[j++] = vowels[idx2]; | ||
961 | if ((i + 1) < rounds) { | ||
962 | idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15; | ||
963 | idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15; | ||
964 | retval[j++] = consonants[idx3]; | ||
965 | retval[j++] = '-'; | ||
966 | retval[j++] = consonants[idx4]; | ||
967 | seed = ((seed * 5) + | ||
968 | ((((u_int)(dgst_raw[2 * i])) * 7) + | ||
969 | ((u_int)(dgst_raw[(2 * i) + 1])))) % 36; | ||
970 | } | ||
971 | } else { | ||
972 | idx0 = seed % 6; | ||
973 | idx1 = 16; | ||
974 | idx2 = seed / 6; | ||
975 | retval[j++] = vowels[idx0]; | ||
976 | retval[j++] = consonants[idx1]; | ||
977 | retval[j++] = vowels[idx2]; | ||
978 | } | ||
979 | } | ||
980 | retval[j++] = 'x'; | ||
981 | retval[j++] = '\0'; | ||
982 | return retval; | ||
983 | } | ||
984 | |||
985 | /* | ||
986 | * Draw an ASCII-Art representing the fingerprint so human brain can | ||
987 | * profit from its built-in pattern recognition ability. | ||
988 | * This technique is called "random art" and can be found in some | ||
989 | * scientific publications like this original paper: | ||
990 | * | ||
991 | * "Hash Visualization: a New Technique to improve Real-World Security", | ||
992 | * Perrig A. and Song D., 1999, International Workshop on Cryptographic | ||
993 | * Techniques and E-Commerce (CrypTEC '99) | ||
994 | * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf | ||
995 | * | ||
996 | * The subject came up in a talk by Dan Kaminsky, too. | ||
997 | * | ||
998 | * If you see the picture is different, the key is different. | ||
999 | * If the picture looks the same, you still know nothing. | ||
1000 | * | ||
1001 | * The algorithm used here is a worm crawling over a discrete plane, | ||
1002 | * leaving a trace (augmenting the field) everywhere it goes. | ||
1003 | * Movement is taken from dgst_raw 2bit-wise. Bumping into walls | ||
1004 | * makes the respective movement vector be ignored for this turn. | ||
1005 | * Graphs are not unambiguous, because circles in graphs can be | ||
1006 | * walked in either direction. | ||
1007 | */ | ||
1008 | |||
1009 | /* | ||
1010 | * Field sizes for the random art. Have to be odd, so the starting point | ||
1011 | * can be in the exact middle of the picture, and FLDBASE should be >=8 . | ||
1012 | * Else pictures would be too dense, and drawing the frame would | ||
1013 | * fail, too, because the key type would not fit in anymore. | ||
1014 | */ | ||
1015 | #define FLDBASE 8 | ||
1016 | #define FLDSIZE_Y (FLDBASE + 1) | ||
1017 | #define FLDSIZE_X (FLDBASE * 2 + 1) | ||
1018 | static char * | ||
1019 | fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len, | ||
1020 | const struct sshkey *k) | ||
1021 | { | ||
1022 | /* | ||
1023 | * Chars to be used after each other every time the worm | ||
1024 | * intersects with itself. Matter of taste. | ||
1025 | */ | ||
1026 | char *augmentation_string = " .o+=*BOX@%&#/^SE"; | ||
1027 | char *retval, *p; | ||
1028 | u_char field[FLDSIZE_X][FLDSIZE_Y]; | ||
1029 | size_t i; | ||
1030 | u_int b; | ||
1031 | int x, y; | ||
1032 | size_t len = strlen(augmentation_string) - 1; | ||
1033 | |||
1034 | if ((retval = calloc((FLDSIZE_X + 3), (FLDSIZE_Y + 2))) == NULL) | ||
1035 | return NULL; | ||
1036 | |||
1037 | /* initialize field */ | ||
1038 | memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char)); | ||
1039 | x = FLDSIZE_X / 2; | ||
1040 | y = FLDSIZE_Y / 2; | ||
1041 | |||
1042 | /* process raw key */ | ||
1043 | for (i = 0; i < dgst_raw_len; i++) { | ||
1044 | int input; | ||
1045 | /* each byte conveys four 2-bit move commands */ | ||
1046 | input = dgst_raw[i]; | ||
1047 | for (b = 0; b < 4; b++) { | ||
1048 | /* evaluate 2 bit, rest is shifted later */ | ||
1049 | x += (input & 0x1) ? 1 : -1; | ||
1050 | y += (input & 0x2) ? 1 : -1; | ||
1051 | |||
1052 | /* assure we are still in bounds */ | ||
1053 | x = MAX(x, 0); | ||
1054 | y = MAX(y, 0); | ||
1055 | x = MIN(x, FLDSIZE_X - 1); | ||
1056 | y = MIN(y, FLDSIZE_Y - 1); | ||
1057 | |||
1058 | /* augment the field */ | ||
1059 | if (field[x][y] < len - 2) | ||
1060 | field[x][y]++; | ||
1061 | input = input >> 2; | ||
1062 | } | ||
1063 | } | ||
1064 | |||
1065 | /* mark starting point and end point*/ | ||
1066 | field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1; | ||
1067 | field[x][y] = len; | ||
1068 | |||
1069 | /* fill in retval */ | ||
1070 | snprintf(retval, FLDSIZE_X, "+--[%4s %4u]", | ||
1071 | sshkey_type(k), sshkey_size(k)); | ||
1072 | p = strchr(retval, '\0'); | ||
1073 | |||
1074 | /* output upper border */ | ||
1075 | for (i = p - retval - 1; i < FLDSIZE_X; i++) | ||
1076 | *p++ = '-'; | ||
1077 | *p++ = '+'; | ||
1078 | *p++ = '\n'; | ||
1079 | |||
1080 | /* output content */ | ||
1081 | for (y = 0; y < FLDSIZE_Y; y++) { | ||
1082 | *p++ = '|'; | ||
1083 | for (x = 0; x < FLDSIZE_X; x++) | ||
1084 | *p++ = augmentation_string[MIN(field[x][y], len)]; | ||
1085 | *p++ = '|'; | ||
1086 | *p++ = '\n'; | ||
1087 | } | ||
1088 | |||
1089 | /* output lower border */ | ||
1090 | *p++ = '+'; | ||
1091 | for (i = 0; i < FLDSIZE_X; i++) | ||
1092 | *p++ = '-'; | ||
1093 | *p++ = '+'; | ||
1094 | |||
1095 | return retval; | ||
1096 | } | ||
1097 | |||
1098 | char * | ||
1099 | sshkey_fingerprint(const struct sshkey *k, enum sshkey_fp_type dgst_type, | ||
1100 | enum sshkey_fp_rep dgst_rep) | ||
1101 | { | ||
1102 | char *retval = NULL; | ||
1103 | u_char *dgst_raw; | ||
1104 | size_t dgst_raw_len; | ||
1105 | |||
1106 | if (sshkey_fingerprint_raw(k, dgst_type, &dgst_raw, &dgst_raw_len) != 0) | ||
1107 | return NULL; | ||
1108 | switch (dgst_rep) { | ||
1109 | case SSH_FP_HEX: | ||
1110 | retval = fingerprint_hex(dgst_raw, dgst_raw_len); | ||
1111 | break; | ||
1112 | case SSH_FP_BUBBLEBABBLE: | ||
1113 | retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len); | ||
1114 | break; | ||
1115 | case SSH_FP_RANDOMART: | ||
1116 | retval = fingerprint_randomart(dgst_raw, dgst_raw_len, k); | ||
1117 | break; | ||
1118 | default: | ||
1119 | explicit_bzero(dgst_raw, dgst_raw_len); | ||
1120 | free(dgst_raw); | ||
1121 | return NULL; | ||
1122 | } | ||
1123 | explicit_bzero(dgst_raw, dgst_raw_len); | ||
1124 | free(dgst_raw); | ||
1125 | return retval; | ||
1126 | } | ||
1127 | |||
1128 | #ifdef WITH_SSH1 | ||
1129 | /* | ||
1130 | * Reads a multiple-precision integer in decimal from the buffer, and advances | ||
1131 | * the pointer. The integer must already be initialized. This function is | ||
1132 | * permitted to modify the buffer. This leaves *cpp to point just beyond the | ||
1133 | * last processed character. | ||
1134 | */ | ||
1135 | static int | ||
1136 | read_decimal_bignum(char **cpp, BIGNUM *v) | ||
1137 | { | ||
1138 | char *cp; | ||
1139 | size_t e; | ||
1140 | int skip = 1; /* skip white space */ | ||
1141 | |||
1142 | cp = *cpp; | ||
1143 | while (*cp == ' ' || *cp == '\t') | ||
1144 | cp++; | ||
1145 | e = strspn(cp, "0123456789"); | ||
1146 | if (e == 0) | ||
1147 | return SSH_ERR_INVALID_FORMAT; | ||
1148 | if (e > SSHBUF_MAX_BIGNUM * 3) | ||
1149 | return SSH_ERR_BIGNUM_TOO_LARGE; | ||
1150 | if (cp[e] == '\0') | ||
1151 | skip = 0; | ||
1152 | else if (index(" \t\r\n", cp[e]) == NULL) | ||
1153 | return SSH_ERR_INVALID_FORMAT; | ||
1154 | cp[e] = '\0'; | ||
1155 | if (BN_dec2bn(&v, cp) <= 0) | ||
1156 | return SSH_ERR_INVALID_FORMAT; | ||
1157 | *cpp = cp + e + skip; | ||
1158 | return 0; | ||
1159 | } | ||
1160 | #endif /* WITH_SSH1 */ | ||
1161 | |||
1162 | /* returns 0 ok, and < 0 error */ | ||
1163 | int | ||
1164 | sshkey_read(struct sshkey *ret, char **cpp) | ||
1165 | { | ||
1166 | struct sshkey *k; | ||
1167 | int retval = SSH_ERR_INVALID_FORMAT; | ||
1168 | char *cp, *space; | ||
1169 | int r, type, curve_nid = -1; | ||
1170 | struct sshbuf *blob; | ||
1171 | #ifdef WITH_SSH1 | ||
1172 | char *ep; | ||
1173 | u_long bits; | ||
1174 | #endif /* WITH_SSH1 */ | ||
1175 | |||
1176 | cp = *cpp; | ||
1177 | |||
1178 | switch (ret->type) { | ||
1179 | case KEY_RSA1: | ||
1180 | #ifdef WITH_SSH1 | ||
1181 | /* Get number of bits. */ | ||
1182 | bits = strtoul(cp, &ep, 10); | ||
1183 | if (*cp == '\0' || index(" \t\r\n", *ep) == NULL || | ||
1184 | bits == 0 || bits > SSHBUF_MAX_BIGNUM * 8) | ||
1185 | return SSH_ERR_INVALID_FORMAT; /* Bad bit count... */ | ||
1186 | /* Get public exponent, public modulus. */ | ||
1187 | if ((r = read_decimal_bignum(&ep, ret->rsa->e)) < 0) | ||
1188 | return r; | ||
1189 | if ((r = read_decimal_bignum(&ep, ret->rsa->n)) < 0) | ||
1190 | return r; | ||
1191 | *cpp = ep; | ||
1192 | /* validate the claimed number of bits */ | ||
1193 | if (BN_num_bits(ret->rsa->n) != (int)bits) | ||
1194 | return SSH_ERR_KEY_BITS_MISMATCH; | ||
1195 | retval = 0; | ||
1196 | #endif /* WITH_SSH1 */ | ||
1197 | break; | ||
1198 | case KEY_UNSPEC: | ||
1199 | case KEY_RSA: | ||
1200 | case KEY_DSA: | ||
1201 | case KEY_ECDSA: | ||
1202 | case KEY_ED25519: | ||
1203 | case KEY_DSA_CERT_V00: | ||
1204 | case KEY_RSA_CERT_V00: | ||
1205 | case KEY_DSA_CERT: | ||
1206 | case KEY_ECDSA_CERT: | ||
1207 | case KEY_RSA_CERT: | ||
1208 | case KEY_ED25519_CERT: | ||
1209 | space = strchr(cp, ' '); | ||
1210 | if (space == NULL) | ||
1211 | return SSH_ERR_INVALID_FORMAT; | ||
1212 | *space = '\0'; | ||
1213 | type = sshkey_type_from_name(cp); | ||
1214 | if (sshkey_type_plain(type) == KEY_ECDSA && | ||
1215 | (curve_nid = sshkey_ecdsa_nid_from_name(cp)) == -1) | ||
1216 | return SSH_ERR_EC_CURVE_INVALID; | ||
1217 | *space = ' '; | ||
1218 | if (type == KEY_UNSPEC) | ||
1219 | return SSH_ERR_INVALID_FORMAT; | ||
1220 | cp = space+1; | ||
1221 | if (*cp == '\0') | ||
1222 | return SSH_ERR_INVALID_FORMAT; | ||
1223 | if (ret->type == KEY_UNSPEC) { | ||
1224 | ret->type = type; | ||
1225 | } else if (ret->type != type) | ||
1226 | return SSH_ERR_KEY_TYPE_MISMATCH; | ||
1227 | if ((blob = sshbuf_new()) == NULL) | ||
1228 | return SSH_ERR_ALLOC_FAIL; | ||
1229 | /* trim comment */ | ||
1230 | space = strchr(cp, ' '); | ||
1231 | if (space) | ||
1232 | *space = '\0'; | ||
1233 | if ((r = sshbuf_b64tod(blob, cp)) != 0) { | ||
1234 | sshbuf_free(blob); | ||
1235 | return r; | ||
1236 | } | ||
1237 | if ((r = sshkey_from_blob(sshbuf_ptr(blob), | ||
1238 | sshbuf_len(blob), &k)) != 0) { | ||
1239 | sshbuf_free(blob); | ||
1240 | return r; | ||
1241 | } | ||
1242 | sshbuf_free(blob); | ||
1243 | if (k->type != type) { | ||
1244 | sshkey_free(k); | ||
1245 | return SSH_ERR_KEY_TYPE_MISMATCH; | ||
1246 | } | ||
1247 | if (sshkey_type_plain(type) == KEY_ECDSA && | ||
1248 | curve_nid != k->ecdsa_nid) { | ||
1249 | sshkey_free(k); | ||
1250 | return SSH_ERR_EC_CURVE_MISMATCH; | ||
1251 | } | ||
1252 | /*XXXX*/ | ||
1253 | if (sshkey_is_cert(ret)) { | ||
1254 | if (!sshkey_is_cert(k)) { | ||
1255 | sshkey_free(k); | ||
1256 | return SSH_ERR_EXPECTED_CERT; | ||
1257 | } | ||
1258 | if (ret->cert != NULL) | ||
1259 | cert_free(ret->cert); | ||
1260 | ret->cert = k->cert; | ||
1261 | k->cert = NULL; | ||
1262 | } | ||
1263 | #ifdef WITH_OPENSSL | ||
1264 | if (sshkey_type_plain(ret->type) == KEY_RSA) { | ||
1265 | if (ret->rsa != NULL) | ||
1266 | RSA_free(ret->rsa); | ||
1267 | ret->rsa = k->rsa; | ||
1268 | k->rsa = NULL; | ||
1269 | #ifdef DEBUG_PK | ||
1270 | RSA_print_fp(stderr, ret->rsa, 8); | ||
1271 | #endif | ||
1272 | } | ||
1273 | if (sshkey_type_plain(ret->type) == KEY_DSA) { | ||
1274 | if (ret->dsa != NULL) | ||
1275 | DSA_free(ret->dsa); | ||
1276 | ret->dsa = k->dsa; | ||
1277 | k->dsa = NULL; | ||
1278 | #ifdef DEBUG_PK | ||
1279 | DSA_print_fp(stderr, ret->dsa, 8); | ||
1280 | #endif | ||
1281 | } | ||
1282 | # ifdef OPENSSL_HAS_ECC | ||
1283 | if (sshkey_type_plain(ret->type) == KEY_ECDSA) { | ||
1284 | if (ret->ecdsa != NULL) | ||
1285 | EC_KEY_free(ret->ecdsa); | ||
1286 | ret->ecdsa = k->ecdsa; | ||
1287 | ret->ecdsa_nid = k->ecdsa_nid; | ||
1288 | k->ecdsa = NULL; | ||
1289 | k->ecdsa_nid = -1; | ||
1290 | #ifdef DEBUG_PK | ||
1291 | sshkey_dump_ec_key(ret->ecdsa); | ||
1292 | #endif | ||
1293 | } | ||
1294 | # endif /* OPENSSL_HAS_ECC */ | ||
1295 | #endif /* WITH_OPENSSL */ | ||
1296 | if (sshkey_type_plain(ret->type) == KEY_ED25519) { | ||
1297 | free(ret->ed25519_pk); | ||
1298 | ret->ed25519_pk = k->ed25519_pk; | ||
1299 | k->ed25519_pk = NULL; | ||
1300 | #ifdef DEBUG_PK | ||
1301 | /* XXX */ | ||
1302 | #endif | ||
1303 | } | ||
1304 | retval = 0; | ||
1305 | /*XXXX*/ | ||
1306 | sshkey_free(k); | ||
1307 | if (retval != 0) | ||
1308 | break; | ||
1309 | /* advance cp: skip whitespace and data */ | ||
1310 | while (*cp == ' ' || *cp == '\t') | ||
1311 | cp++; | ||
1312 | while (*cp != '\0' && *cp != ' ' && *cp != '\t') | ||
1313 | cp++; | ||
1314 | *cpp = cp; | ||
1315 | break; | ||
1316 | default: | ||
1317 | return SSH_ERR_INVALID_ARGUMENT; | ||
1318 | } | ||
1319 | return retval; | ||
1320 | } | ||
1321 | |||
1322 | int | ||
1323 | sshkey_write(const struct sshkey *key, FILE *f) | ||
1324 | { | ||
1325 | int ret = SSH_ERR_INTERNAL_ERROR; | ||
1326 | struct sshbuf *b = NULL, *bb = NULL; | ||
1327 | char *uu = NULL; | ||
1328 | #ifdef WITH_SSH1 | ||
1329 | u_int bits = 0; | ||
1330 | char *dec_e = NULL, *dec_n = NULL; | ||
1331 | #endif /* WITH_SSH1 */ | ||
1332 | |||
1333 | if (sshkey_is_cert(key)) { | ||
1334 | if (key->cert == NULL) | ||
1335 | return SSH_ERR_EXPECTED_CERT; | ||
1336 | if (sshbuf_len(key->cert->certblob) == 0) | ||
1337 | return SSH_ERR_KEY_LACKS_CERTBLOB; | ||
1338 | } | ||
1339 | if ((b = sshbuf_new()) == NULL) | ||
1340 | return SSH_ERR_ALLOC_FAIL; | ||
1341 | switch (key->type) { | ||
1342 | #ifdef WITH_SSH1 | ||
1343 | case KEY_RSA1: | ||
1344 | if (key->rsa == NULL || key->rsa->e == NULL || | ||
1345 | key->rsa->n == NULL) { | ||
1346 | ret = SSH_ERR_INVALID_ARGUMENT; | ||
1347 | goto out; | ||
1348 | } | ||
1349 | if ((dec_e = BN_bn2dec(key->rsa->e)) == NULL || | ||
1350 | (dec_n = BN_bn2dec(key->rsa->n)) == NULL) { | ||
1351 | ret = SSH_ERR_ALLOC_FAIL; | ||
1352 | goto out; | ||
1353 | } | ||
1354 | /* size of modulus 'n' */ | ||
1355 | if ((bits = BN_num_bits(key->rsa->n)) <= 0) { | ||
1356 | ret = SSH_ERR_INVALID_ARGUMENT; | ||
1357 | goto out; | ||
1358 | } | ||
1359 | if ((ret = sshbuf_putf(b, "%u %s %s", bits, dec_e, dec_n)) != 0) | ||
1360 | goto out; | ||
1361 | #endif /* WITH_SSH1 */ | ||
1362 | break; | ||
1363 | #ifdef WITH_OPENSSL | ||
1364 | case KEY_DSA: | ||
1365 | case KEY_DSA_CERT_V00: | ||
1366 | case KEY_DSA_CERT: | ||
1367 | case KEY_ECDSA: | ||
1368 | case KEY_ECDSA_CERT: | ||
1369 | case KEY_RSA: | ||
1370 | case KEY_RSA_CERT_V00: | ||
1371 | case KEY_RSA_CERT: | ||
1372 | #endif /* WITH_OPENSSL */ | ||
1373 | case KEY_ED25519: | ||
1374 | case KEY_ED25519_CERT: | ||
1375 | if ((bb = sshbuf_new()) == NULL) { | ||
1376 | ret = SSH_ERR_ALLOC_FAIL; | ||
1377 | goto out; | ||
1378 | } | ||
1379 | if ((ret = sshkey_to_blob_buf(key, bb)) != 0) | ||
1380 | goto out; | ||
1381 | if ((uu = sshbuf_dtob64(bb)) == NULL) { | ||
1382 | ret = SSH_ERR_ALLOC_FAIL; | ||
1383 | goto out; | ||
1384 | } | ||
1385 | if ((ret = sshbuf_putf(b, "%s ", sshkey_ssh_name(key))) != 0) | ||
1386 | goto out; | ||
1387 | if ((ret = sshbuf_put(b, uu, strlen(uu))) != 0) | ||
1388 | goto out; | ||
1389 | break; | ||
1390 | default: | ||
1391 | ret = SSH_ERR_KEY_TYPE_UNKNOWN; | ||
1392 | goto out; | ||
1393 | } | ||
1394 | if (fwrite(sshbuf_ptr(b), sshbuf_len(b), 1, f) != 1) { | ||
1395 | if (feof(f)) | ||
1396 | errno = EPIPE; | ||
1397 | ret = SSH_ERR_SYSTEM_ERROR; | ||
1398 | goto out; | ||
1399 | } | ||
1400 | ret = 0; | ||
1401 | out: | ||
1402 | if (b != NULL) | ||
1403 | sshbuf_free(b); | ||
1404 | if (bb != NULL) | ||
1405 | sshbuf_free(bb); | ||
1406 | if (uu != NULL) | ||
1407 | free(uu); | ||
1408 | #ifdef WITH_SSH1 | ||
1409 | if (dec_e != NULL) | ||
1410 | OPENSSL_free(dec_e); | ||
1411 | if (dec_n != NULL) | ||
1412 | OPENSSL_free(dec_n); | ||
1413 | #endif /* WITH_SSH1 */ | ||
1414 | return ret; | ||
1415 | } | ||
1416 | |||
1417 | const char * | ||
1418 | sshkey_cert_type(const struct sshkey *k) | ||
1419 | { | ||
1420 | switch (k->cert->type) { | ||
1421 | case SSH2_CERT_TYPE_USER: | ||
1422 | return "user"; | ||
1423 | case SSH2_CERT_TYPE_HOST: | ||
1424 | return "host"; | ||
1425 | default: | ||
1426 | return "unknown"; | ||
1427 | } | ||
1428 | } | ||
1429 | |||
1430 | #ifdef WITH_OPENSSL | ||
1431 | static int | ||
1432 | rsa_generate_private_key(u_int bits, RSA **rsap) | ||
1433 | { | ||
1434 | RSA *private = NULL; | ||
1435 | BIGNUM *f4 = NULL; | ||
1436 | int ret = SSH_ERR_INTERNAL_ERROR; | ||
1437 | |||
1438 | if (rsap == NULL || | ||
1439 | bits < SSH_RSA_MINIMUM_MODULUS_SIZE || | ||
1440 | bits > SSHBUF_MAX_BIGNUM * 8) | ||
1441 | return SSH_ERR_INVALID_ARGUMENT; | ||
1442 | *rsap = NULL; | ||
1443 | if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) { | ||
1444 | ret = SSH_ERR_ALLOC_FAIL; | ||
1445 | goto out; | ||
1446 | } | ||
1447 | if (!BN_set_word(f4, RSA_F4) || | ||
1448 | !RSA_generate_key_ex(private, bits, f4, NULL)) { | ||
1449 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
1450 | goto out; | ||
1451 | } | ||
1452 | *rsap = private; | ||
1453 | private = NULL; | ||
1454 | ret = 0; | ||
1455 | out: | ||
1456 | if (private != NULL) | ||
1457 | RSA_free(private); | ||
1458 | if (f4 != NULL) | ||
1459 | BN_free(f4); | ||
1460 | return ret; | ||
1461 | } | ||
1462 | |||
1463 | static int | ||
1464 | dsa_generate_private_key(u_int bits, DSA **dsap) | ||
1465 | { | ||
1466 | DSA *private; | ||
1467 | int ret = SSH_ERR_INTERNAL_ERROR; | ||
1468 | |||
1469 | if (dsap == NULL || bits != 1024) | ||
1470 | return SSH_ERR_INVALID_ARGUMENT; | ||
1471 | if ((private = DSA_new()) == NULL) { | ||
1472 | ret = SSH_ERR_ALLOC_FAIL; | ||
1473 | goto out; | ||
1474 | } | ||
1475 | *dsap = NULL; | ||
1476 | if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL, | ||
1477 | NULL, NULL) || !DSA_generate_key(private)) { | ||
1478 | DSA_free(private); | ||
1479 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
1480 | goto out; | ||
1481 | } | ||
1482 | *dsap = private; | ||
1483 | private = NULL; | ||
1484 | ret = 0; | ||
1485 | out: | ||
1486 | if (private != NULL) | ||
1487 | DSA_free(private); | ||
1488 | return ret; | ||
1489 | } | ||
1490 | |||
1491 | # ifdef OPENSSL_HAS_ECC | ||
1492 | int | ||
1493 | sshkey_ecdsa_key_to_nid(EC_KEY *k) | ||
1494 | { | ||
1495 | EC_GROUP *eg; | ||
1496 | int nids[] = { | ||
1497 | NID_X9_62_prime256v1, | ||
1498 | NID_secp384r1, | ||
1499 | # ifdef OPENSSL_HAS_NISTP521 | ||
1500 | NID_secp521r1, | ||
1501 | # endif /* OPENSSL_HAS_NISTP521 */ | ||
1502 | -1 | ||
1503 | }; | ||
1504 | int nid; | ||
1505 | u_int i; | ||
1506 | BN_CTX *bnctx; | ||
1507 | const EC_GROUP *g = EC_KEY_get0_group(k); | ||
1508 | |||
1509 | /* | ||
1510 | * The group may be stored in a ASN.1 encoded private key in one of two | ||
1511 | * ways: as a "named group", which is reconstituted by ASN.1 object ID | ||
1512 | * or explicit group parameters encoded into the key blob. Only the | ||
1513 | * "named group" case sets the group NID for us, but we can figure | ||
1514 | * it out for the other case by comparing against all the groups that | ||
1515 | * are supported. | ||
1516 | */ | ||
1517 | if ((nid = EC_GROUP_get_curve_name(g)) > 0) | ||
1518 | return nid; | ||
1519 | if ((bnctx = BN_CTX_new()) == NULL) | ||
1520 | return -1; | ||
1521 | for (i = 0; nids[i] != -1; i++) { | ||
1522 | if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL) { | ||
1523 | BN_CTX_free(bnctx); | ||
1524 | return -1; | ||
1525 | } | ||
1526 | if (EC_GROUP_cmp(g, eg, bnctx) == 0) | ||
1527 | break; | ||
1528 | EC_GROUP_free(eg); | ||
1529 | } | ||
1530 | BN_CTX_free(bnctx); | ||
1531 | if (nids[i] != -1) { | ||
1532 | /* Use the group with the NID attached */ | ||
1533 | EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE); | ||
1534 | if (EC_KEY_set_group(k, eg) != 1) { | ||
1535 | EC_GROUP_free(eg); | ||
1536 | return -1; | ||
1537 | } | ||
1538 | } | ||
1539 | return nids[i]; | ||
1540 | } | ||
1541 | |||
1542 | static int | ||
1543 | ecdsa_generate_private_key(u_int bits, int *nid, EC_KEY **ecdsap) | ||
1544 | { | ||
1545 | EC_KEY *private; | ||
1546 | int ret = SSH_ERR_INTERNAL_ERROR; | ||
1547 | |||
1548 | if (nid == NULL || ecdsap == NULL || | ||
1549 | (*nid = sshkey_ecdsa_bits_to_nid(bits)) == -1) | ||
1550 | return SSH_ERR_INVALID_ARGUMENT; | ||
1551 | *ecdsap = NULL; | ||
1552 | if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL) { | ||
1553 | ret = SSH_ERR_ALLOC_FAIL; | ||
1554 | goto out; | ||
1555 | } | ||
1556 | if (EC_KEY_generate_key(private) != 1) { | ||
1557 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
1558 | goto out; | ||
1559 | } | ||
1560 | EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE); | ||
1561 | *ecdsap = private; | ||
1562 | private = NULL; | ||
1563 | ret = 0; | ||
1564 | out: | ||
1565 | if (private != NULL) | ||
1566 | EC_KEY_free(private); | ||
1567 | return ret; | ||
1568 | } | ||
1569 | # endif /* OPENSSL_HAS_ECC */ | ||
1570 | #endif /* WITH_OPENSSL */ | ||
1571 | |||
1572 | int | ||
1573 | sshkey_generate(int type, u_int bits, struct sshkey **keyp) | ||
1574 | { | ||
1575 | struct sshkey *k; | ||
1576 | int ret = SSH_ERR_INTERNAL_ERROR; | ||
1577 | |||
1578 | if (keyp == NULL) | ||
1579 | return SSH_ERR_INVALID_ARGUMENT; | ||
1580 | *keyp = NULL; | ||
1581 | if ((k = sshkey_new(KEY_UNSPEC)) == NULL) | ||
1582 | return SSH_ERR_ALLOC_FAIL; | ||
1583 | switch (type) { | ||
1584 | case KEY_ED25519: | ||
1585 | if ((k->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL || | ||
1586 | (k->ed25519_sk = malloc(ED25519_SK_SZ)) == NULL) { | ||
1587 | ret = SSH_ERR_ALLOC_FAIL; | ||
1588 | break; | ||
1589 | } | ||
1590 | crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk); | ||
1591 | ret = 0; | ||
1592 | break; | ||
1593 | #ifdef WITH_OPENSSL | ||
1594 | case KEY_DSA: | ||
1595 | ret = dsa_generate_private_key(bits, &k->dsa); | ||
1596 | break; | ||
1597 | # ifdef OPENSSL_HAS_ECC | ||
1598 | case KEY_ECDSA: | ||
1599 | ret = ecdsa_generate_private_key(bits, &k->ecdsa_nid, | ||
1600 | &k->ecdsa); | ||
1601 | break; | ||
1602 | # endif /* OPENSSL_HAS_ECC */ | ||
1603 | case KEY_RSA: | ||
1604 | case KEY_RSA1: | ||
1605 | ret = rsa_generate_private_key(bits, &k->rsa); | ||
1606 | break; | ||
1607 | #endif /* WITH_OPENSSL */ | ||
1608 | default: | ||
1609 | ret = SSH_ERR_INVALID_ARGUMENT; | ||
1610 | } | ||
1611 | if (ret == 0) { | ||
1612 | k->type = type; | ||
1613 | *keyp = k; | ||
1614 | } else | ||
1615 | sshkey_free(k); | ||
1616 | return ret; | ||
1617 | } | ||
1618 | |||
1619 | int | ||
1620 | sshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key) | ||
1621 | { | ||
1622 | u_int i; | ||
1623 | const struct sshkey_cert *from; | ||
1624 | struct sshkey_cert *to; | ||
1625 | int ret = SSH_ERR_INTERNAL_ERROR; | ||
1626 | |||
1627 | if (to_key->cert != NULL) { | ||
1628 | cert_free(to_key->cert); | ||
1629 | to_key->cert = NULL; | ||
1630 | } | ||
1631 | |||
1632 | if ((from = from_key->cert) == NULL) | ||
1633 | return SSH_ERR_INVALID_ARGUMENT; | ||
1634 | |||
1635 | if ((to = to_key->cert = cert_new()) == NULL) | ||
1636 | return SSH_ERR_ALLOC_FAIL; | ||
1637 | |||
1638 | if ((ret = sshbuf_putb(to->certblob, from->certblob)) != 0 || | ||
1639 | (ret = sshbuf_putb(to->critical, from->critical)) != 0 || | ||
1640 | (ret = sshbuf_putb(to->extensions, from->extensions) != 0)) | ||
1641 | return ret; | ||
1642 | |||
1643 | to->serial = from->serial; | ||
1644 | to->type = from->type; | ||
1645 | if (from->key_id == NULL) | ||
1646 | to->key_id = NULL; | ||
1647 | else if ((to->key_id = strdup(from->key_id)) == NULL) | ||
1648 | return SSH_ERR_ALLOC_FAIL; | ||
1649 | to->valid_after = from->valid_after; | ||
1650 | to->valid_before = from->valid_before; | ||
1651 | if (from->signature_key == NULL) | ||
1652 | to->signature_key = NULL; | ||
1653 | else if ((ret = sshkey_from_private(from->signature_key, | ||
1654 | &to->signature_key)) != 0) | ||
1655 | return ret; | ||
1656 | |||
1657 | if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS) | ||
1658 | return SSH_ERR_INVALID_ARGUMENT; | ||
1659 | if (from->nprincipals > 0) { | ||
1660 | if ((to->principals = calloc(from->nprincipals, | ||
1661 | sizeof(*to->principals))) == NULL) | ||
1662 | return SSH_ERR_ALLOC_FAIL; | ||
1663 | for (i = 0; i < from->nprincipals; i++) { | ||
1664 | to->principals[i] = strdup(from->principals[i]); | ||
1665 | if (to->principals[i] == NULL) { | ||
1666 | to->nprincipals = i; | ||
1667 | return SSH_ERR_ALLOC_FAIL; | ||
1668 | } | ||
1669 | } | ||
1670 | } | ||
1671 | to->nprincipals = from->nprincipals; | ||
1672 | return 0; | ||
1673 | } | ||
1674 | |||
1675 | int | ||
1676 | sshkey_from_private(const struct sshkey *k, struct sshkey **pkp) | ||
1677 | { | ||
1678 | struct sshkey *n = NULL; | ||
1679 | int ret = SSH_ERR_INTERNAL_ERROR; | ||
1680 | |||
1681 | if (pkp != NULL) | ||
1682 | *pkp = NULL; | ||
1683 | |||
1684 | switch (k->type) { | ||
1685 | #ifdef WITH_OPENSSL | ||
1686 | case KEY_DSA: | ||
1687 | case KEY_DSA_CERT_V00: | ||
1688 | case KEY_DSA_CERT: | ||
1689 | if ((n = sshkey_new(k->type)) == NULL) | ||
1690 | return SSH_ERR_ALLOC_FAIL; | ||
1691 | if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) || | ||
1692 | (BN_copy(n->dsa->q, k->dsa->q) == NULL) || | ||
1693 | (BN_copy(n->dsa->g, k->dsa->g) == NULL) || | ||
1694 | (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL)) { | ||
1695 | sshkey_free(n); | ||
1696 | return SSH_ERR_ALLOC_FAIL; | ||
1697 | } | ||
1698 | break; | ||
1699 | # ifdef OPENSSL_HAS_ECC | ||
1700 | case KEY_ECDSA: | ||
1701 | case KEY_ECDSA_CERT: | ||
1702 | if ((n = sshkey_new(k->type)) == NULL) | ||
1703 | return SSH_ERR_ALLOC_FAIL; | ||
1704 | n->ecdsa_nid = k->ecdsa_nid; | ||
1705 | n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid); | ||
1706 | if (n->ecdsa == NULL) { | ||
1707 | sshkey_free(n); | ||
1708 | return SSH_ERR_ALLOC_FAIL; | ||
1709 | } | ||
1710 | if (EC_KEY_set_public_key(n->ecdsa, | ||
1711 | EC_KEY_get0_public_key(k->ecdsa)) != 1) { | ||
1712 | sshkey_free(n); | ||
1713 | return SSH_ERR_LIBCRYPTO_ERROR; | ||
1714 | } | ||
1715 | break; | ||
1716 | # endif /* OPENSSL_HAS_ECC */ | ||
1717 | case KEY_RSA: | ||
1718 | case KEY_RSA1: | ||
1719 | case KEY_RSA_CERT_V00: | ||
1720 | case KEY_RSA_CERT: | ||
1721 | if ((n = sshkey_new(k->type)) == NULL) | ||
1722 | return SSH_ERR_ALLOC_FAIL; | ||
1723 | if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) || | ||
1724 | (BN_copy(n->rsa->e, k->rsa->e) == NULL)) { | ||
1725 | sshkey_free(n); | ||
1726 | return SSH_ERR_ALLOC_FAIL; | ||
1727 | } | ||
1728 | break; | ||
1729 | #endif /* WITH_OPENSSL */ | ||
1730 | case KEY_ED25519: | ||
1731 | case KEY_ED25519_CERT: | ||
1732 | if ((n = sshkey_new(k->type)) == NULL) | ||
1733 | return SSH_ERR_ALLOC_FAIL; | ||
1734 | if (k->ed25519_pk != NULL) { | ||
1735 | if ((n->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) { | ||
1736 | sshkey_free(n); | ||
1737 | return SSH_ERR_ALLOC_FAIL; | ||
1738 | } | ||
1739 | memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); | ||
1740 | } | ||
1741 | break; | ||
1742 | default: | ||
1743 | return SSH_ERR_KEY_TYPE_UNKNOWN; | ||
1744 | } | ||
1745 | if (sshkey_is_cert(k)) { | ||
1746 | if ((ret = sshkey_cert_copy(k, n)) != 0) { | ||
1747 | sshkey_free(n); | ||
1748 | return ret; | ||
1749 | } | ||
1750 | } | ||
1751 | *pkp = n; | ||
1752 | return 0; | ||
1753 | } | ||
1754 | |||
1755 | static int | ||
1756 | cert_parse(struct sshbuf *b, struct sshkey *key, const u_char *blob, | ||
1757 | size_t blen) | ||
1758 | { | ||
1759 | u_char *principals = NULL, *critical = NULL, *exts = NULL; | ||
1760 | u_char *sig_key = NULL, *sig = NULL; | ||
1761 | size_t signed_len, plen, clen, sklen, slen, kidlen, elen; | ||
1762 | struct sshbuf *tmp; | ||
1763 | char *principal; | ||
1764 | int ret = SSH_ERR_INTERNAL_ERROR; | ||
1765 | int v00 = sshkey_cert_is_legacy(key); | ||
1766 | char **oprincipals; | ||
1767 | |||
1768 | if ((tmp = sshbuf_new()) == NULL) | ||
1769 | return SSH_ERR_ALLOC_FAIL; | ||
1770 | |||
1771 | /* Copy the entire key blob for verification and later serialisation */ | ||
1772 | if ((ret = sshbuf_put(key->cert->certblob, blob, blen)) != 0) | ||
1773 | return ret; | ||
1774 | |||
1775 | elen = 0; /* Not touched for v00 certs */ | ||
1776 | principals = exts = critical = sig_key = sig = NULL; | ||
1777 | if ((!v00 && (ret = sshbuf_get_u64(b, &key->cert->serial)) != 0) || | ||
1778 | (ret = sshbuf_get_u32(b, &key->cert->type)) != 0 || | ||
1779 | (ret = sshbuf_get_cstring(b, &key->cert->key_id, &kidlen)) != 0 || | ||
1780 | (ret = sshbuf_get_string(b, &principals, &plen)) != 0 || | ||
1781 | (ret = sshbuf_get_u64(b, &key->cert->valid_after)) != 0 || | ||
1782 | (ret = sshbuf_get_u64(b, &key->cert->valid_before)) != 0 || | ||
1783 | (ret = sshbuf_get_string(b, &critical, &clen)) != 0 || | ||
1784 | (!v00 && (ret = sshbuf_get_string(b, &exts, &elen)) != 0) || | ||
1785 | (v00 && (ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0) || | ||
1786 | (ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0 || | ||
1787 | (ret = sshbuf_get_string(b, &sig_key, &sklen)) != 0) { | ||
1788 | /* XXX debug print error for ret */ | ||
1789 | ret = SSH_ERR_INVALID_FORMAT; | ||
1790 | goto out; | ||
1791 | } | ||
1792 | |||
1793 | /* Signature is left in the buffer so we can calculate this length */ | ||
1794 | signed_len = sshbuf_len(key->cert->certblob) - sshbuf_len(b); | ||
1795 | |||
1796 | if ((ret = sshbuf_get_string(b, &sig, &slen)) != 0) { | ||
1797 | ret = SSH_ERR_INVALID_FORMAT; | ||
1798 | goto out; | ||
1799 | } | ||
1800 | |||
1801 | if (key->cert->type != SSH2_CERT_TYPE_USER && | ||
1802 | key->cert->type != SSH2_CERT_TYPE_HOST) { | ||
1803 | ret = SSH_ERR_KEY_CERT_UNKNOWN_TYPE; | ||
1804 | goto out; | ||
1805 | } | ||
1806 | |||
1807 | if ((ret = sshbuf_put(tmp, principals, plen)) != 0) | ||
1808 | goto out; | ||
1809 | while (sshbuf_len(tmp) > 0) { | ||
1810 | if (key->cert->nprincipals >= SSHKEY_CERT_MAX_PRINCIPALS) { | ||
1811 | ret = SSH_ERR_INVALID_FORMAT; | ||
1812 | goto out; | ||
1813 | } | ||
1814 | if ((ret = sshbuf_get_cstring(tmp, &principal, &plen)) != 0) { | ||
1815 | ret = SSH_ERR_INVALID_FORMAT; | ||
1816 | goto out; | ||
1817 | } | ||
1818 | oprincipals = key->cert->principals; | ||
1819 | key->cert->principals = realloc(key->cert->principals, | ||
1820 | (key->cert->nprincipals + 1) * | ||
1821 | sizeof(*key->cert->principals)); | ||
1822 | if (key->cert->principals == NULL) { | ||
1823 | free(principal); | ||
1824 | key->cert->principals = oprincipals; | ||
1825 | ret = SSH_ERR_ALLOC_FAIL; | ||
1826 | goto out; | ||
1827 | } | ||
1828 | key->cert->principals[key->cert->nprincipals++] = principal; | ||
1829 | } | ||
1830 | |||
1831 | sshbuf_reset(tmp); | ||
1832 | |||
1833 | if ((ret = sshbuf_put(key->cert->critical, critical, clen)) != 0 || | ||
1834 | (ret = sshbuf_put(tmp, critical, clen)) != 0) | ||
1835 | goto out; | ||
1836 | |||
1837 | /* validate structure */ | ||
1838 | while (sshbuf_len(tmp) != 0) { | ||
1839 | if ((ret = sshbuf_get_string_direct(tmp, NULL, NULL)) != 0 || | ||
1840 | (ret = sshbuf_get_string_direct(tmp, NULL, NULL)) != 0) { | ||
1841 | ret = SSH_ERR_INVALID_FORMAT; | ||
1842 | goto out; | ||
1843 | } | ||
1844 | } | ||
1845 | sshbuf_reset(tmp); | ||
1846 | |||
1847 | if ((ret = sshbuf_put(key->cert->extensions, exts, elen)) != 0 || | ||
1848 | (ret = sshbuf_put(tmp, exts, elen)) != 0) | ||
1849 | goto out; | ||
1850 | |||
1851 | /* validate structure */ | ||
1852 | while (sshbuf_len(tmp) != 0) { | ||
1853 | if ((ret = sshbuf_get_string_direct(tmp, NULL, NULL)) != 0 || | ||
1854 | (ret = sshbuf_get_string_direct(tmp, NULL, NULL)) != 0) { | ||
1855 | ret = SSH_ERR_INVALID_FORMAT; | ||
1856 | goto out; | ||
1857 | } | ||
1858 | } | ||
1859 | sshbuf_reset(tmp); | ||
1860 | |||
1861 | if (sshkey_from_blob_internal(sig_key, sklen, | ||
1862 | &key->cert->signature_key, 0) != 0) { | ||
1863 | ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; | ||
1864 | goto out; | ||
1865 | } | ||
1866 | if (!sshkey_type_is_valid_ca(key->cert->signature_key->type)) { | ||
1867 | ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; | ||
1868 | goto out; | ||
1869 | } | ||
1870 | |||
1871 | if ((ret = sshkey_verify(key->cert->signature_key, sig, slen, | ||
1872 | sshbuf_ptr(key->cert->certblob), signed_len, 0)) != 0) | ||
1873 | goto out; | ||
1874 | ret = 0; | ||
1875 | |||
1876 | out: | ||
1877 | sshbuf_free(tmp); | ||
1878 | free(principals); | ||
1879 | free(critical); | ||
1880 | free(exts); | ||
1881 | free(sig_key); | ||
1882 | free(sig); | ||
1883 | return ret; | ||
1884 | } | ||
1885 | |||
1886 | static int | ||
1887 | sshkey_from_blob_internal(const u_char *blob, size_t blen, | ||
1888 | struct sshkey **keyp, int allow_cert) | ||
1889 | { | ||
1890 | struct sshbuf *b = NULL; | ||
1891 | int type, nid = -1, ret = SSH_ERR_INTERNAL_ERROR; | ||
1892 | char *ktype = NULL, *curve = NULL; | ||
1893 | struct sshkey *key = NULL; | ||
1894 | size_t len; | ||
1895 | u_char *pk = NULL; | ||
1896 | #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) | ||
1897 | EC_POINT *q = NULL; | ||
1898 | #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ | ||
1899 | |||
1900 | #ifdef DEBUG_PK /* XXX */ | ||
1901 | dump_base64(stderr, blob, blen); | ||
1902 | #endif | ||
1903 | *keyp = NULL; | ||
1904 | if ((b = sshbuf_from(blob, blen)) == NULL) | ||
1905 | return SSH_ERR_ALLOC_FAIL; | ||
1906 | if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { | ||
1907 | ret = SSH_ERR_INVALID_FORMAT; | ||
1908 | goto out; | ||
1909 | } | ||
1910 | |||
1911 | type = sshkey_type_from_name(ktype); | ||
1912 | if (sshkey_type_plain(type) == KEY_ECDSA) | ||
1913 | nid = sshkey_ecdsa_nid_from_name(ktype); | ||
1914 | if (!allow_cert && sshkey_type_is_cert(type)) { | ||
1915 | ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; | ||
1916 | goto out; | ||
1917 | } | ||
1918 | switch (type) { | ||
1919 | #ifdef WITH_OPENSSL | ||
1920 | case KEY_RSA_CERT: | ||
1921 | if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { | ||
1922 | ret = SSH_ERR_INVALID_FORMAT; | ||
1923 | goto out; | ||
1924 | } | ||
1925 | /* FALLTHROUGH */ | ||
1926 | case KEY_RSA: | ||
1927 | case KEY_RSA_CERT_V00: | ||
1928 | if ((key = sshkey_new(type)) == NULL) { | ||
1929 | ret = SSH_ERR_ALLOC_FAIL; | ||
1930 | goto out; | ||
1931 | } | ||
1932 | if (sshbuf_get_bignum2(b, key->rsa->e) == -1 || | ||
1933 | sshbuf_get_bignum2(b, key->rsa->n) == -1) { | ||
1934 | ret = SSH_ERR_INVALID_FORMAT; | ||
1935 | goto out; | ||
1936 | } | ||
1937 | #ifdef DEBUG_PK | ||
1938 | RSA_print_fp(stderr, key->rsa, 8); | ||
1939 | #endif | ||
1940 | break; | ||
1941 | case KEY_DSA_CERT: | ||
1942 | if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { | ||
1943 | ret = SSH_ERR_INVALID_FORMAT; | ||
1944 | goto out; | ||
1945 | } | ||
1946 | /* FALLTHROUGH */ | ||
1947 | case KEY_DSA: | ||
1948 | case KEY_DSA_CERT_V00: | ||
1949 | if ((key = sshkey_new(type)) == NULL) { | ||
1950 | ret = SSH_ERR_ALLOC_FAIL; | ||
1951 | goto out; | ||
1952 | } | ||
1953 | if (sshbuf_get_bignum2(b, key->dsa->p) == -1 || | ||
1954 | sshbuf_get_bignum2(b, key->dsa->q) == -1 || | ||
1955 | sshbuf_get_bignum2(b, key->dsa->g) == -1 || | ||
1956 | sshbuf_get_bignum2(b, key->dsa->pub_key) == -1) { | ||
1957 | ret = SSH_ERR_INVALID_FORMAT; | ||
1958 | goto out; | ||
1959 | } | ||
1960 | #ifdef DEBUG_PK | ||
1961 | DSA_print_fp(stderr, key->dsa, 8); | ||
1962 | #endif | ||
1963 | break; | ||
1964 | case KEY_ECDSA_CERT: | ||
1965 | if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { | ||
1966 | ret = SSH_ERR_INVALID_FORMAT; | ||
1967 | goto out; | ||
1968 | } | ||
1969 | /* FALLTHROUGH */ | ||
1970 | # ifdef OPENSSL_HAS_ECC | ||
1971 | case KEY_ECDSA: | ||
1972 | if ((key = sshkey_new(type)) == NULL) { | ||
1973 | ret = SSH_ERR_ALLOC_FAIL; | ||
1974 | goto out; | ||
1975 | } | ||
1976 | key->ecdsa_nid = nid; | ||
1977 | if (sshbuf_get_cstring(b, &curve, NULL) != 0) { | ||
1978 | ret = SSH_ERR_INVALID_FORMAT; | ||
1979 | goto out; | ||
1980 | } | ||
1981 | if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) { | ||
1982 | ret = SSH_ERR_EC_CURVE_MISMATCH; | ||
1983 | goto out; | ||
1984 | } | ||
1985 | if (key->ecdsa != NULL) | ||
1986 | EC_KEY_free(key->ecdsa); | ||
1987 | if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid)) | ||
1988 | == NULL) { | ||
1989 | ret = SSH_ERR_EC_CURVE_INVALID; | ||
1990 | goto out; | ||
1991 | } | ||
1992 | if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL) { | ||
1993 | ret = SSH_ERR_ALLOC_FAIL; | ||
1994 | goto out; | ||
1995 | } | ||
1996 | if (sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa)) != 0) { | ||
1997 | ret = SSH_ERR_INVALID_FORMAT; | ||
1998 | goto out; | ||
1999 | } | ||
2000 | if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa), | ||
2001 | q) != 0) { | ||
2002 | ret = SSH_ERR_KEY_INVALID_EC_VALUE; | ||
2003 | goto out; | ||
2004 | } | ||
2005 | if (EC_KEY_set_public_key(key->ecdsa, q) != 1) { | ||
2006 | /* XXX assume it is a allocation error */ | ||
2007 | ret = SSH_ERR_ALLOC_FAIL; | ||
2008 | goto out; | ||
2009 | } | ||
2010 | #ifdef DEBUG_PK | ||
2011 | sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q); | ||
2012 | #endif | ||
2013 | break; | ||
2014 | # endif /* OPENSSL_HAS_ECC */ | ||
2015 | #endif /* WITH_OPENSSL */ | ||
2016 | case KEY_ED25519_CERT: | ||
2017 | if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { | ||
2018 | ret = SSH_ERR_INVALID_FORMAT; | ||
2019 | goto out; | ||
2020 | } | ||
2021 | /* FALLTHROUGH */ | ||
2022 | case KEY_ED25519: | ||
2023 | if ((ret = sshbuf_get_string(b, &pk, &len)) != 0) | ||
2024 | goto out; | ||
2025 | if (len != ED25519_PK_SZ) { | ||
2026 | ret = SSH_ERR_INVALID_FORMAT; | ||
2027 | goto out; | ||
2028 | } | ||
2029 | if ((key = sshkey_new(type)) == NULL) { | ||
2030 | ret = SSH_ERR_ALLOC_FAIL; | ||
2031 | goto out; | ||
2032 | } | ||
2033 | key->ed25519_pk = pk; | ||
2034 | pk = NULL; | ||
2035 | break; | ||
2036 | case KEY_UNSPEC: | ||
2037 | if ((key = sshkey_new(type)) == NULL) { | ||
2038 | ret = SSH_ERR_ALLOC_FAIL; | ||
2039 | goto out; | ||
2040 | } | ||
2041 | break; | ||
2042 | default: | ||
2043 | ret = SSH_ERR_KEY_TYPE_UNKNOWN; | ||
2044 | goto out; | ||
2045 | } | ||
2046 | |||
2047 | /* Parse certificate potion */ | ||
2048 | if (sshkey_is_cert(key) && | ||
2049 | (ret = cert_parse(b, key, blob, blen)) != 0) | ||
2050 | goto out; | ||
2051 | |||
2052 | if (key != NULL && sshbuf_len(b) != 0) { | ||
2053 | ret = SSH_ERR_INVALID_FORMAT; | ||
2054 | goto out; | ||
2055 | } | ||
2056 | ret = 0; | ||
2057 | *keyp = key; | ||
2058 | key = NULL; | ||
2059 | out: | ||
2060 | sshbuf_free(b); | ||
2061 | sshkey_free(key); | ||
2062 | free(ktype); | ||
2063 | free(curve); | ||
2064 | free(pk); | ||
2065 | #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) | ||
2066 | if (q != NULL) | ||
2067 | EC_POINT_free(q); | ||
2068 | #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ | ||
2069 | return ret; | ||
2070 | } | ||
2071 | |||
2072 | int | ||
2073 | sshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp) | ||
2074 | { | ||
2075 | return sshkey_from_blob_internal(blob, blen, keyp, 1); | ||
2076 | } | ||
2077 | |||
2078 | int | ||
2079 | sshkey_sign(const struct sshkey *key, | ||
2080 | u_char **sigp, size_t *lenp, | ||
2081 | const u_char *data, size_t datalen, u_int compat) | ||
2082 | { | ||
2083 | if (sigp != NULL) | ||
2084 | *sigp = NULL; | ||
2085 | if (lenp != NULL) | ||
2086 | *lenp = 0; | ||
2087 | if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) | ||
2088 | return SSH_ERR_INVALID_ARGUMENT; | ||
2089 | switch (key->type) { | ||
2090 | #ifdef WITH_OPENSSL | ||
2091 | case KEY_DSA_CERT_V00: | ||
2092 | case KEY_DSA_CERT: | ||
2093 | case KEY_DSA: | ||
2094 | return ssh_dss_sign(key, sigp, lenp, data, datalen, compat); | ||
2095 | # ifdef OPENSSL_HAS_ECC | ||
2096 | case KEY_ECDSA_CERT: | ||
2097 | case KEY_ECDSA: | ||
2098 | return ssh_ecdsa_sign(key, sigp, lenp, data, datalen, compat); | ||
2099 | # endif /* OPENSSL_HAS_ECC */ | ||
2100 | case KEY_RSA_CERT_V00: | ||
2101 | case KEY_RSA_CERT: | ||
2102 | case KEY_RSA: | ||
2103 | return ssh_rsa_sign(key, sigp, lenp, data, datalen, compat); | ||
2104 | #endif /* WITH_OPENSSL */ | ||
2105 | case KEY_ED25519: | ||
2106 | case KEY_ED25519_CERT: | ||
2107 | return ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat); | ||
2108 | default: | ||
2109 | return SSH_ERR_KEY_TYPE_UNKNOWN; | ||
2110 | } | ||
2111 | } | ||
2112 | |||
2113 | /* | ||
2114 | * ssh_key_verify returns 0 for a correct signature and < 0 on error. | ||
2115 | */ | ||
2116 | int | ||
2117 | sshkey_verify(const struct sshkey *key, | ||
2118 | const u_char *sig, size_t siglen, | ||
2119 | const u_char *data, size_t dlen, u_int compat) | ||
2120 | { | ||
2121 | if (siglen == 0) | ||
2122 | return -1; | ||
2123 | |||
2124 | if (dlen > SSH_KEY_MAX_SIGN_DATA_SIZE) | ||
2125 | return SSH_ERR_INVALID_ARGUMENT; | ||
2126 | switch (key->type) { | ||
2127 | #ifdef WITH_OPENSSL | ||
2128 | case KEY_DSA_CERT_V00: | ||
2129 | case KEY_DSA_CERT: | ||
2130 | case KEY_DSA: | ||
2131 | return ssh_dss_verify(key, sig, siglen, data, dlen, compat); | ||
2132 | # ifdef OPENSSL_HAS_ECC | ||
2133 | case KEY_ECDSA_CERT: | ||
2134 | case KEY_ECDSA: | ||
2135 | return ssh_ecdsa_verify(key, sig, siglen, data, dlen, compat); | ||
2136 | # endif /* OPENSSL_HAS_ECC */ | ||
2137 | case KEY_RSA_CERT_V00: | ||
2138 | case KEY_RSA_CERT: | ||
2139 | case KEY_RSA: | ||
2140 | return ssh_rsa_verify(key, sig, siglen, data, dlen, compat); | ||
2141 | #endif /* WITH_OPENSSL */ | ||
2142 | case KEY_ED25519: | ||
2143 | case KEY_ED25519_CERT: | ||
2144 | return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat); | ||
2145 | default: | ||
2146 | return SSH_ERR_KEY_TYPE_UNKNOWN; | ||
2147 | } | ||
2148 | } | ||
2149 | |||
2150 | /* Converts a private to a public key */ | ||
2151 | int | ||
2152 | sshkey_demote(const struct sshkey *k, struct sshkey **dkp) | ||
2153 | { | ||
2154 | struct sshkey *pk; | ||
2155 | int ret = SSH_ERR_INTERNAL_ERROR; | ||
2156 | |||
2157 | if (dkp != NULL) | ||
2158 | *dkp = NULL; | ||
2159 | |||
2160 | if ((pk = calloc(1, sizeof(*pk))) == NULL) | ||
2161 | return SSH_ERR_ALLOC_FAIL; | ||
2162 | pk->type = k->type; | ||
2163 | pk->flags = k->flags; | ||
2164 | pk->ecdsa_nid = k->ecdsa_nid; | ||
2165 | pk->dsa = NULL; | ||
2166 | pk->ecdsa = NULL; | ||
2167 | pk->rsa = NULL; | ||
2168 | pk->ed25519_pk = NULL; | ||
2169 | pk->ed25519_sk = NULL; | ||
2170 | |||
2171 | switch (k->type) { | ||
2172 | #ifdef WITH_OPENSSL | ||
2173 | case KEY_RSA_CERT_V00: | ||
2174 | case KEY_RSA_CERT: | ||
2175 | if ((ret = sshkey_cert_copy(k, pk)) != 0) | ||
2176 | goto fail; | ||
2177 | /* FALLTHROUGH */ | ||
2178 | case KEY_RSA1: | ||
2179 | case KEY_RSA: | ||
2180 | if ((pk->rsa = RSA_new()) == NULL || | ||
2181 | (pk->rsa->e = BN_dup(k->rsa->e)) == NULL || | ||
2182 | (pk->rsa->n = BN_dup(k->rsa->n)) == NULL) { | ||
2183 | ret = SSH_ERR_ALLOC_FAIL; | ||
2184 | goto fail; | ||
2185 | } | ||
2186 | break; | ||
2187 | case KEY_DSA_CERT_V00: | ||
2188 | case KEY_DSA_CERT: | ||
2189 | if ((ret = sshkey_cert_copy(k, pk)) != 0) | ||
2190 | goto fail; | ||
2191 | /* FALLTHROUGH */ | ||
2192 | case KEY_DSA: | ||
2193 | if ((pk->dsa = DSA_new()) == NULL || | ||
2194 | (pk->dsa->p = BN_dup(k->dsa->p)) == NULL || | ||
2195 | (pk->dsa->q = BN_dup(k->dsa->q)) == NULL || | ||
2196 | (pk->dsa->g = BN_dup(k->dsa->g)) == NULL || | ||
2197 | (pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) { | ||
2198 | ret = SSH_ERR_ALLOC_FAIL; | ||
2199 | goto fail; | ||
2200 | } | ||
2201 | break; | ||
2202 | case KEY_ECDSA_CERT: | ||
2203 | if ((ret = sshkey_cert_copy(k, pk)) != 0) | ||
2204 | goto fail; | ||
2205 | /* FALLTHROUGH */ | ||
2206 | # ifdef OPENSSL_HAS_ECC | ||
2207 | case KEY_ECDSA: | ||
2208 | pk->ecdsa = EC_KEY_new_by_curve_name(pk->ecdsa_nid); | ||
2209 | if (pk->ecdsa == NULL) { | ||
2210 | ret = SSH_ERR_ALLOC_FAIL; | ||
2211 | goto fail; | ||
2212 | } | ||
2213 | if (EC_KEY_set_public_key(pk->ecdsa, | ||
2214 | EC_KEY_get0_public_key(k->ecdsa)) != 1) { | ||
2215 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
2216 | goto fail; | ||
2217 | } | ||
2218 | break; | ||
2219 | # endif /* OPENSSL_HAS_ECC */ | ||
2220 | #endif /* WITH_OPENSSL */ | ||
2221 | case KEY_ED25519_CERT: | ||
2222 | if ((ret = sshkey_cert_copy(k, pk)) != 0) | ||
2223 | goto fail; | ||
2224 | /* FALLTHROUGH */ | ||
2225 | case KEY_ED25519: | ||
2226 | if (k->ed25519_pk != NULL) { | ||
2227 | if ((pk->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) { | ||
2228 | ret = SSH_ERR_ALLOC_FAIL; | ||
2229 | goto fail; | ||
2230 | } | ||
2231 | memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); | ||
2232 | } | ||
2233 | break; | ||
2234 | default: | ||
2235 | ret = SSH_ERR_KEY_TYPE_UNKNOWN; | ||
2236 | fail: | ||
2237 | sshkey_free(pk); | ||
2238 | return ret; | ||
2239 | } | ||
2240 | *dkp = pk; | ||
2241 | return 0; | ||
2242 | } | ||
2243 | |||
2244 | /* Convert a plain key to their _CERT equivalent */ | ||
2245 | int | ||
2246 | sshkey_to_certified(struct sshkey *k, int legacy) | ||
2247 | { | ||
2248 | int newtype; | ||
2249 | |||
2250 | switch (k->type) { | ||
2251 | #ifdef WITH_OPENSSL | ||
2252 | case KEY_RSA: | ||
2253 | newtype = legacy ? KEY_RSA_CERT_V00 : KEY_RSA_CERT; | ||
2254 | break; | ||
2255 | case KEY_DSA: | ||
2256 | newtype = legacy ? KEY_DSA_CERT_V00 : KEY_DSA_CERT; | ||
2257 | break; | ||
2258 | case KEY_ECDSA: | ||
2259 | if (legacy) | ||
2260 | return SSH_ERR_INVALID_ARGUMENT; | ||
2261 | newtype = KEY_ECDSA_CERT; | ||
2262 | break; | ||
2263 | #endif /* WITH_OPENSSL */ | ||
2264 | case KEY_ED25519: | ||
2265 | if (legacy) | ||
2266 | return SSH_ERR_INVALID_ARGUMENT; | ||
2267 | newtype = KEY_ED25519_CERT; | ||
2268 | break; | ||
2269 | default: | ||
2270 | return SSH_ERR_INVALID_ARGUMENT; | ||
2271 | } | ||
2272 | if ((k->cert = cert_new()) == NULL) | ||
2273 | return SSH_ERR_ALLOC_FAIL; | ||
2274 | k->type = newtype; | ||
2275 | return 0; | ||
2276 | } | ||
2277 | |||
2278 | /* Convert a certificate to its raw key equivalent */ | ||
2279 | int | ||
2280 | sshkey_drop_cert(struct sshkey *k) | ||
2281 | { | ||
2282 | if (!sshkey_type_is_cert(k->type)) | ||
2283 | return SSH_ERR_KEY_TYPE_UNKNOWN; | ||
2284 | cert_free(k->cert); | ||
2285 | k->cert = NULL; | ||
2286 | k->type = sshkey_type_plain(k->type); | ||
2287 | return 0; | ||
2288 | } | ||
2289 | |||
2290 | /* Sign a certified key, (re-)generating the signed certblob. */ | ||
2291 | int | ||
2292 | sshkey_certify(struct sshkey *k, struct sshkey *ca) | ||
2293 | { | ||
2294 | struct sshbuf *principals = NULL; | ||
2295 | u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32]; | ||
2296 | size_t i, ca_len, sig_len; | ||
2297 | int ret = SSH_ERR_INTERNAL_ERROR; | ||
2298 | struct sshbuf *cert; | ||
2299 | |||
2300 | if (k == NULL || k->cert == NULL || | ||
2301 | k->cert->certblob == NULL || ca == NULL) | ||
2302 | return SSH_ERR_INVALID_ARGUMENT; | ||
2303 | if (!sshkey_is_cert(k)) | ||
2304 | return SSH_ERR_KEY_TYPE_UNKNOWN; | ||
2305 | if (!sshkey_type_is_valid_ca(ca->type)) | ||
2306 | return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; | ||
2307 | |||
2308 | if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0) | ||
2309 | return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; | ||
2310 | |||
2311 | cert = k->cert->certblob; /* for readability */ | ||
2312 | sshbuf_reset(cert); | ||
2313 | if ((ret = sshbuf_put_cstring(cert, sshkey_ssh_name(k))) != 0) | ||
2314 | goto out; | ||
2315 | |||
2316 | /* -v01 certs put nonce first */ | ||
2317 | arc4random_buf(&nonce, sizeof(nonce)); | ||
2318 | if (!sshkey_cert_is_legacy(k)) { | ||
2319 | if ((ret = sshbuf_put_string(cert, nonce, sizeof(nonce))) != 0) | ||
2320 | goto out; | ||
2321 | } | ||
2322 | |||
2323 | /* XXX this substantially duplicates to_blob(); refactor */ | ||
2324 | switch (k->type) { | ||
2325 | #ifdef WITH_OPENSSL | ||
2326 | case KEY_DSA_CERT_V00: | ||
2327 | case KEY_DSA_CERT: | ||
2328 | if ((ret = sshbuf_put_bignum2(cert, k->dsa->p)) != 0 || | ||
2329 | (ret = sshbuf_put_bignum2(cert, k->dsa->q)) != 0 || | ||
2330 | (ret = sshbuf_put_bignum2(cert, k->dsa->g)) != 0 || | ||
2331 | (ret = sshbuf_put_bignum2(cert, k->dsa->pub_key)) != 0) | ||
2332 | goto out; | ||
2333 | break; | ||
2334 | # ifdef OPENSSL_HAS_ECC | ||
2335 | case KEY_ECDSA_CERT: | ||
2336 | if ((ret = sshbuf_put_cstring(cert, | ||
2337 | sshkey_curve_nid_to_name(k->ecdsa_nid))) != 0 || | ||
2338 | (ret = sshbuf_put_ec(cert, | ||
2339 | EC_KEY_get0_public_key(k->ecdsa), | ||
2340 | EC_KEY_get0_group(k->ecdsa))) != 0) | ||
2341 | goto out; | ||
2342 | break; | ||
2343 | # endif /* OPENSSL_HAS_ECC */ | ||
2344 | case KEY_RSA_CERT_V00: | ||
2345 | case KEY_RSA_CERT: | ||
2346 | if ((ret = sshbuf_put_bignum2(cert, k->rsa->e)) != 0 || | ||
2347 | (ret = sshbuf_put_bignum2(cert, k->rsa->n)) != 0) | ||
2348 | goto out; | ||
2349 | break; | ||
2350 | #endif /* WITH_OPENSSL */ | ||
2351 | case KEY_ED25519_CERT: | ||
2352 | if ((ret = sshbuf_put_string(cert, | ||
2353 | k->ed25519_pk, ED25519_PK_SZ)) != 0) | ||
2354 | goto out; | ||
2355 | break; | ||
2356 | default: | ||
2357 | ret = SSH_ERR_INVALID_ARGUMENT; | ||
2358 | } | ||
2359 | |||
2360 | /* -v01 certs have a serial number next */ | ||
2361 | if (!sshkey_cert_is_legacy(k)) { | ||
2362 | if ((ret = sshbuf_put_u64(cert, k->cert->serial)) != 0) | ||
2363 | goto out; | ||
2364 | } | ||
2365 | |||
2366 | if ((ret = sshbuf_put_u32(cert, k->cert->type)) != 0 || | ||
2367 | (ret = sshbuf_put_cstring(cert, k->cert->key_id)) != 0) | ||
2368 | goto out; | ||
2369 | |||
2370 | if ((principals = sshbuf_new()) == NULL) { | ||
2371 | ret = SSH_ERR_ALLOC_FAIL; | ||
2372 | goto out; | ||
2373 | } | ||
2374 | for (i = 0; i < k->cert->nprincipals; i++) { | ||
2375 | if ((ret = sshbuf_put_cstring(principals, | ||
2376 | k->cert->principals[i])) != 0) | ||
2377 | goto out; | ||
2378 | } | ||
2379 | if ((ret = sshbuf_put_stringb(cert, principals)) != 0 || | ||
2380 | (ret = sshbuf_put_u64(cert, k->cert->valid_after)) != 0 || | ||
2381 | (ret = sshbuf_put_u64(cert, k->cert->valid_before)) != 0 || | ||
2382 | (ret = sshbuf_put_stringb(cert, k->cert->critical)) != 0) | ||
2383 | goto out; | ||
2384 | |||
2385 | /* -v01 certs have non-critical options here */ | ||
2386 | if (!sshkey_cert_is_legacy(k)) { | ||
2387 | if ((ret = sshbuf_put_stringb(cert, k->cert->extensions)) != 0) | ||
2388 | goto out; | ||
2389 | } | ||
2390 | |||
2391 | /* -v00 certs put the nonce at the end */ | ||
2392 | if (sshkey_cert_is_legacy(k)) { | ||
2393 | if ((ret = sshbuf_put_string(cert, nonce, sizeof(nonce))) != 0) | ||
2394 | goto out; | ||
2395 | } | ||
2396 | |||
2397 | if ((ret = sshbuf_put_string(cert, NULL, 0)) != 0 || /* Reserved */ | ||
2398 | (ret = sshbuf_put_string(cert, ca_blob, ca_len)) != 0) | ||
2399 | goto out; | ||
2400 | |||
2401 | /* Sign the whole mess */ | ||
2402 | if ((ret = sshkey_sign(ca, &sig_blob, &sig_len, sshbuf_ptr(cert), | ||
2403 | sshbuf_len(cert), 0)) != 0) | ||
2404 | goto out; | ||
2405 | |||
2406 | /* Append signature and we are done */ | ||
2407 | if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0) | ||
2408 | goto out; | ||
2409 | ret = 0; | ||
2410 | out: | ||
2411 | if (ret != 0) | ||
2412 | sshbuf_reset(cert); | ||
2413 | if (sig_blob != NULL) | ||
2414 | free(sig_blob); | ||
2415 | if (ca_blob != NULL) | ||
2416 | free(ca_blob); | ||
2417 | if (principals != NULL) | ||
2418 | sshbuf_free(principals); | ||
2419 | return ret; | ||
2420 | } | ||
2421 | |||
2422 | int | ||
2423 | sshkey_cert_check_authority(const struct sshkey *k, | ||
2424 | int want_host, int require_principal, | ||
2425 | const char *name, const char **reason) | ||
2426 | { | ||
2427 | u_int i, principal_matches; | ||
2428 | time_t now = time(NULL); | ||
2429 | |||
2430 | if (reason != NULL) | ||
2431 | *reason = NULL; | ||
2432 | |||
2433 | if (want_host) { | ||
2434 | if (k->cert->type != SSH2_CERT_TYPE_HOST) { | ||
2435 | *reason = "Certificate invalid: not a host certificate"; | ||
2436 | return SSH_ERR_KEY_CERT_INVALID; | ||
2437 | } | ||
2438 | } else { | ||
2439 | if (k->cert->type != SSH2_CERT_TYPE_USER) { | ||
2440 | *reason = "Certificate invalid: not a user certificate"; | ||
2441 | return SSH_ERR_KEY_CERT_INVALID; | ||
2442 | } | ||
2443 | } | ||
2444 | if (now < 0) { | ||
2445 | /* yikes - system clock before epoch! */ | ||
2446 | *reason = "Certificate invalid: not yet valid"; | ||
2447 | return SSH_ERR_KEY_CERT_INVALID; | ||
2448 | } | ||
2449 | if ((u_int64_t)now < k->cert->valid_after) { | ||
2450 | *reason = "Certificate invalid: not yet valid"; | ||
2451 | return SSH_ERR_KEY_CERT_INVALID; | ||
2452 | } | ||
2453 | if ((u_int64_t)now >= k->cert->valid_before) { | ||
2454 | *reason = "Certificate invalid: expired"; | ||
2455 | return SSH_ERR_KEY_CERT_INVALID; | ||
2456 | } | ||
2457 | if (k->cert->nprincipals == 0) { | ||
2458 | if (require_principal) { | ||
2459 | *reason = "Certificate lacks principal list"; | ||
2460 | return SSH_ERR_KEY_CERT_INVALID; | ||
2461 | } | ||
2462 | } else if (name != NULL) { | ||
2463 | principal_matches = 0; | ||
2464 | for (i = 0; i < k->cert->nprincipals; i++) { | ||
2465 | if (strcmp(name, k->cert->principals[i]) == 0) { | ||
2466 | principal_matches = 1; | ||
2467 | break; | ||
2468 | } | ||
2469 | } | ||
2470 | if (!principal_matches) { | ||
2471 | *reason = "Certificate invalid: name is not a listed " | ||
2472 | "principal"; | ||
2473 | return SSH_ERR_KEY_CERT_INVALID; | ||
2474 | } | ||
2475 | } | ||
2476 | return 0; | ||
2477 | } | ||
2478 | |||
2479 | int | ||
2480 | sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b) | ||
2481 | { | ||
2482 | int r = SSH_ERR_INTERNAL_ERROR; | ||
2483 | |||
2484 | if ((r = sshbuf_put_cstring(b, sshkey_ssh_name(key))) != 0) | ||
2485 | goto out; | ||
2486 | switch (key->type) { | ||
2487 | #ifdef WITH_OPENSSL | ||
2488 | case KEY_RSA: | ||
2489 | if ((r = sshbuf_put_bignum2(b, key->rsa->n)) != 0 || | ||
2490 | (r = sshbuf_put_bignum2(b, key->rsa->e)) != 0 || | ||
2491 | (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 || | ||
2492 | (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 || | ||
2493 | (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 || | ||
2494 | (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0) | ||
2495 | goto out; | ||
2496 | break; | ||
2497 | case KEY_RSA_CERT_V00: | ||
2498 | case KEY_RSA_CERT: | ||
2499 | if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { | ||
2500 | r = SSH_ERR_INVALID_ARGUMENT; | ||
2501 | goto out; | ||
2502 | } | ||
2503 | if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || | ||
2504 | (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 || | ||
2505 | (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 || | ||
2506 | (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 || | ||
2507 | (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0) | ||
2508 | goto out; | ||
2509 | break; | ||
2510 | case KEY_DSA: | ||
2511 | if ((r = sshbuf_put_bignum2(b, key->dsa->p)) != 0 || | ||
2512 | (r = sshbuf_put_bignum2(b, key->dsa->q)) != 0 || | ||
2513 | (r = sshbuf_put_bignum2(b, key->dsa->g)) != 0 || | ||
2514 | (r = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0 || | ||
2515 | (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0) | ||
2516 | goto out; | ||
2517 | break; | ||
2518 | case KEY_DSA_CERT_V00: | ||
2519 | case KEY_DSA_CERT: | ||
2520 | if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { | ||
2521 | r = SSH_ERR_INVALID_ARGUMENT; | ||
2522 | goto out; | ||
2523 | } | ||
2524 | if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || | ||
2525 | (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0) | ||
2526 | goto out; | ||
2527 | break; | ||
2528 | # ifdef OPENSSL_HAS_ECC | ||
2529 | case KEY_ECDSA: | ||
2530 | if ((r = sshbuf_put_cstring(b, | ||
2531 | sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || | ||
2532 | (r = sshbuf_put_eckey(b, key->ecdsa)) != 0 || | ||
2533 | (r = sshbuf_put_bignum2(b, | ||
2534 | EC_KEY_get0_private_key(key->ecdsa))) != 0) | ||
2535 | goto out; | ||
2536 | break; | ||
2537 | case KEY_ECDSA_CERT: | ||
2538 | if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { | ||
2539 | r = SSH_ERR_INVALID_ARGUMENT; | ||
2540 | goto out; | ||
2541 | } | ||
2542 | if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || | ||
2543 | (r = sshbuf_put_bignum2(b, | ||
2544 | EC_KEY_get0_private_key(key->ecdsa))) != 0) | ||
2545 | goto out; | ||
2546 | break; | ||
2547 | # endif /* OPENSSL_HAS_ECC */ | ||
2548 | #endif /* WITH_OPENSSL */ | ||
2549 | case KEY_ED25519: | ||
2550 | if ((r = sshbuf_put_string(b, key->ed25519_pk, | ||
2551 | ED25519_PK_SZ)) != 0 || | ||
2552 | (r = sshbuf_put_string(b, key->ed25519_sk, | ||
2553 | ED25519_SK_SZ)) != 0) | ||
2554 | goto out; | ||
2555 | break; | ||
2556 | case KEY_ED25519_CERT: | ||
2557 | if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { | ||
2558 | r = SSH_ERR_INVALID_ARGUMENT; | ||
2559 | goto out; | ||
2560 | } | ||
2561 | if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || | ||
2562 | (r = sshbuf_put_string(b, key->ed25519_pk, | ||
2563 | ED25519_PK_SZ)) != 0 || | ||
2564 | (r = sshbuf_put_string(b, key->ed25519_sk, | ||
2565 | ED25519_SK_SZ)) != 0) | ||
2566 | goto out; | ||
2567 | break; | ||
2568 | default: | ||
2569 | r = SSH_ERR_INVALID_ARGUMENT; | ||
2570 | goto out; | ||
2571 | } | ||
2572 | /* success */ | ||
2573 | r = 0; | ||
2574 | out: | ||
2575 | return r; | ||
2576 | } | ||
2577 | |||
2578 | int | ||
2579 | sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) | ||
2580 | { | ||
2581 | char *tname = NULL, *curve = NULL; | ||
2582 | struct sshkey *k = NULL; | ||
2583 | const u_char *cert; | ||
2584 | size_t len, pklen = 0, sklen = 0; | ||
2585 | int type, r = SSH_ERR_INTERNAL_ERROR; | ||
2586 | u_char *ed25519_pk = NULL, *ed25519_sk = NULL; | ||
2587 | #ifdef WITH_OPENSSL | ||
2588 | BIGNUM *exponent = NULL; | ||
2589 | #endif /* WITH_OPENSSL */ | ||
2590 | |||
2591 | if (kp != NULL) | ||
2592 | *kp = NULL; | ||
2593 | if ((r = sshbuf_get_cstring(buf, &tname, NULL)) != 0) | ||
2594 | goto out; | ||
2595 | type = sshkey_type_from_name(tname); | ||
2596 | switch (type) { | ||
2597 | #ifdef WITH_OPENSSL | ||
2598 | case KEY_DSA: | ||
2599 | if ((k = sshkey_new_private(type)) == NULL) { | ||
2600 | r = SSH_ERR_ALLOC_FAIL; | ||
2601 | goto out; | ||
2602 | } | ||
2603 | if ((r = sshbuf_get_bignum2(buf, k->dsa->p)) != 0 || | ||
2604 | (r = sshbuf_get_bignum2(buf, k->dsa->q)) != 0 || | ||
2605 | (r = sshbuf_get_bignum2(buf, k->dsa->g)) != 0 || | ||
2606 | (r = sshbuf_get_bignum2(buf, k->dsa->pub_key)) != 0 || | ||
2607 | (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0) | ||
2608 | goto out; | ||
2609 | break; | ||
2610 | case KEY_DSA_CERT_V00: | ||
2611 | case KEY_DSA_CERT: | ||
2612 | if ((r = sshbuf_get_string_direct(buf, &cert, &len)) != 0 || | ||
2613 | (r = sshkey_from_blob(cert, len, &k)) != 0 || | ||
2614 | (r = sshkey_add_private(k)) != 0 || | ||
2615 | (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0) | ||
2616 | goto out; | ||
2617 | break; | ||
2618 | # ifdef OPENSSL_HAS_ECC | ||
2619 | case KEY_ECDSA: | ||
2620 | if ((k = sshkey_new_private(type)) == NULL) { | ||
2621 | r = SSH_ERR_ALLOC_FAIL; | ||
2622 | goto out; | ||
2623 | } | ||
2624 | if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) { | ||
2625 | r = SSH_ERR_INVALID_ARGUMENT; | ||
2626 | goto out; | ||
2627 | } | ||
2628 | if ((r = sshbuf_get_cstring(buf, &curve, NULL)) != 0) | ||
2629 | goto out; | ||
2630 | if (k->ecdsa_nid != sshkey_curve_name_to_nid(curve)) { | ||
2631 | r = SSH_ERR_EC_CURVE_MISMATCH; | ||
2632 | goto out; | ||
2633 | } | ||
2634 | k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid); | ||
2635 | if (k->ecdsa == NULL || (exponent = BN_new()) == NULL) { | ||
2636 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
2637 | goto out; | ||
2638 | } | ||
2639 | if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0 || | ||
2640 | (r = sshbuf_get_bignum2(buf, exponent))) | ||
2641 | goto out; | ||
2642 | if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) { | ||
2643 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
2644 | goto out; | ||
2645 | } | ||
2646 | if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa), | ||
2647 | EC_KEY_get0_public_key(k->ecdsa)) != 0) || | ||
2648 | (r = sshkey_ec_validate_private(k->ecdsa)) != 0) | ||
2649 | goto out; | ||
2650 | break; | ||
2651 | case KEY_ECDSA_CERT: | ||
2652 | if ((exponent = BN_new()) == NULL) { | ||
2653 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
2654 | goto out; | ||
2655 | } | ||
2656 | if ((r = sshbuf_get_string_direct(buf, &cert, &len)) != 0 || | ||
2657 | (r = sshkey_from_blob(cert, len, &k)) != 0 || | ||
2658 | (r = sshkey_add_private(k)) != 0 || | ||
2659 | (r = sshbuf_get_bignum2(buf, exponent)) != 0) | ||
2660 | goto out; | ||
2661 | if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) { | ||
2662 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
2663 | goto out; | ||
2664 | } | ||
2665 | if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa), | ||
2666 | EC_KEY_get0_public_key(k->ecdsa)) != 0) || | ||
2667 | (r = sshkey_ec_validate_private(k->ecdsa)) != 0) | ||
2668 | goto out; | ||
2669 | break; | ||
2670 | # endif /* OPENSSL_HAS_ECC */ | ||
2671 | case KEY_RSA: | ||
2672 | if ((k = sshkey_new_private(type)) == NULL) { | ||
2673 | r = SSH_ERR_ALLOC_FAIL; | ||
2674 | goto out; | ||
2675 | } | ||
2676 | if ((r = sshbuf_get_bignum2(buf, k->rsa->n)) != 0 || | ||
2677 | (r = sshbuf_get_bignum2(buf, k->rsa->e)) != 0 || | ||
2678 | (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 || | ||
2679 | (r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 || | ||
2680 | (r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 || | ||
2681 | (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 || | ||
2682 | (r = rsa_generate_additional_parameters(k->rsa)) != 0) | ||
2683 | goto out; | ||
2684 | break; | ||
2685 | case KEY_RSA_CERT_V00: | ||
2686 | case KEY_RSA_CERT: | ||
2687 | if ((r = sshbuf_get_string_direct(buf, &cert, &len)) != 0 || | ||
2688 | (r = sshkey_from_blob(cert, len, &k)) != 0 || | ||
2689 | (r = sshkey_add_private(k)) != 0 || | ||
2690 | (r = sshbuf_get_bignum2(buf, k->rsa->d) != 0) || | ||
2691 | (r = sshbuf_get_bignum2(buf, k->rsa->iqmp) != 0) || | ||
2692 | (r = sshbuf_get_bignum2(buf, k->rsa->p) != 0) || | ||
2693 | (r = sshbuf_get_bignum2(buf, k->rsa->q) != 0) || | ||
2694 | (r = rsa_generate_additional_parameters(k->rsa)) != 0) | ||
2695 | goto out; | ||
2696 | break; | ||
2697 | #endif /* WITH_OPENSSL */ | ||
2698 | case KEY_ED25519: | ||
2699 | if ((k = sshkey_new_private(type)) == NULL) { | ||
2700 | r = SSH_ERR_ALLOC_FAIL; | ||
2701 | goto out; | ||
2702 | } | ||
2703 | if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 || | ||
2704 | (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0) | ||
2705 | goto out; | ||
2706 | if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) { | ||
2707 | r = SSH_ERR_INVALID_FORMAT; | ||
2708 | goto out; | ||
2709 | } | ||
2710 | k->ed25519_pk = ed25519_pk; | ||
2711 | k->ed25519_sk = ed25519_sk; | ||
2712 | ed25519_pk = ed25519_sk = NULL; | ||
2713 | break; | ||
2714 | case KEY_ED25519_CERT: | ||
2715 | if ((r = sshbuf_get_string_direct(buf, &cert, &len)) != 0 || | ||
2716 | (r = sshkey_from_blob(cert, len, &k)) != 0 || | ||
2717 | (r = sshkey_add_private(k)) != 0 || | ||
2718 | (r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 || | ||
2719 | (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0) | ||
2720 | goto out; | ||
2721 | if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) { | ||
2722 | r = SSH_ERR_INVALID_FORMAT; | ||
2723 | goto out; | ||
2724 | } | ||
2725 | k->ed25519_pk = ed25519_pk; | ||
2726 | k->ed25519_sk = ed25519_sk; | ||
2727 | ed25519_pk = ed25519_sk = NULL; | ||
2728 | break; | ||
2729 | default: | ||
2730 | r = SSH_ERR_KEY_TYPE_UNKNOWN; | ||
2731 | goto out; | ||
2732 | } | ||
2733 | #ifdef WITH_OPENSSL | ||
2734 | /* enable blinding */ | ||
2735 | switch (k->type) { | ||
2736 | case KEY_RSA: | ||
2737 | case KEY_RSA_CERT_V00: | ||
2738 | case KEY_RSA_CERT: | ||
2739 | case KEY_RSA1: | ||
2740 | if (RSA_blinding_on(k->rsa, NULL) != 1) { | ||
2741 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
2742 | goto out; | ||
2743 | } | ||
2744 | break; | ||
2745 | } | ||
2746 | #endif /* WITH_OPENSSL */ | ||
2747 | /* success */ | ||
2748 | r = 0; | ||
2749 | if (kp != NULL) { | ||
2750 | *kp = k; | ||
2751 | k = NULL; | ||
2752 | } | ||
2753 | out: | ||
2754 | free(tname); | ||
2755 | free(curve); | ||
2756 | #ifdef WITH_OPENSSL | ||
2757 | if (exponent != NULL) | ||
2758 | BN_clear_free(exponent); | ||
2759 | #endif /* WITH_OPENSSL */ | ||
2760 | sshkey_free(k); | ||
2761 | if (ed25519_pk != NULL) { | ||
2762 | explicit_bzero(ed25519_pk, pklen); | ||
2763 | free(ed25519_pk); | ||
2764 | } | ||
2765 | if (ed25519_sk != NULL) { | ||
2766 | explicit_bzero(ed25519_sk, sklen); | ||
2767 | free(ed25519_sk); | ||
2768 | } | ||
2769 | return r; | ||
2770 | } | ||
2771 | |||
2772 | #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) | ||
2773 | int | ||
2774 | sshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public) | ||
2775 | { | ||
2776 | BN_CTX *bnctx; | ||
2777 | EC_POINT *nq = NULL; | ||
2778 | BIGNUM *order, *x, *y, *tmp; | ||
2779 | int ret = SSH_ERR_KEY_INVALID_EC_VALUE; | ||
2780 | |||
2781 | if ((bnctx = BN_CTX_new()) == NULL) | ||
2782 | return SSH_ERR_ALLOC_FAIL; | ||
2783 | BN_CTX_start(bnctx); | ||
2784 | |||
2785 | /* | ||
2786 | * We shouldn't ever hit this case because bignum_get_ecpoint() | ||
2787 | * refuses to load GF2m points. | ||
2788 | */ | ||
2789 | if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != | ||
2790 | NID_X9_62_prime_field) | ||
2791 | goto out; | ||
2792 | |||
2793 | /* Q != infinity */ | ||
2794 | if (EC_POINT_is_at_infinity(group, public)) | ||
2795 | goto out; | ||
2796 | |||
2797 | if ((x = BN_CTX_get(bnctx)) == NULL || | ||
2798 | (y = BN_CTX_get(bnctx)) == NULL || | ||
2799 | (order = BN_CTX_get(bnctx)) == NULL || | ||
2800 | (tmp = BN_CTX_get(bnctx)) == NULL) { | ||
2801 | ret = SSH_ERR_ALLOC_FAIL; | ||
2802 | goto out; | ||
2803 | } | ||
2804 | |||
2805 | /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */ | ||
2806 | if (EC_GROUP_get_order(group, order, bnctx) != 1 || | ||
2807 | EC_POINT_get_affine_coordinates_GFp(group, public, | ||
2808 | x, y, bnctx) != 1) { | ||
2809 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
2810 | goto out; | ||
2811 | } | ||
2812 | if (BN_num_bits(x) <= BN_num_bits(order) / 2 || | ||
2813 | BN_num_bits(y) <= BN_num_bits(order) / 2) | ||
2814 | goto out; | ||
2815 | |||
2816 | /* nQ == infinity (n == order of subgroup) */ | ||
2817 | if ((nq = EC_POINT_new(group)) == NULL) { | ||
2818 | ret = SSH_ERR_ALLOC_FAIL; | ||
2819 | goto out; | ||
2820 | } | ||
2821 | if (EC_POINT_mul(group, nq, NULL, public, order, bnctx) != 1) { | ||
2822 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
2823 | goto out; | ||
2824 | } | ||
2825 | if (EC_POINT_is_at_infinity(group, nq) != 1) | ||
2826 | goto out; | ||
2827 | |||
2828 | /* x < order - 1, y < order - 1 */ | ||
2829 | if (!BN_sub(tmp, order, BN_value_one())) { | ||
2830 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
2831 | goto out; | ||
2832 | } | ||
2833 | if (BN_cmp(x, tmp) >= 0 || BN_cmp(y, tmp) >= 0) | ||
2834 | goto out; | ||
2835 | ret = 0; | ||
2836 | out: | ||
2837 | BN_CTX_free(bnctx); | ||
2838 | if (nq != NULL) | ||
2839 | EC_POINT_free(nq); | ||
2840 | return ret; | ||
2841 | } | ||
2842 | |||
2843 | int | ||
2844 | sshkey_ec_validate_private(const EC_KEY *key) | ||
2845 | { | ||
2846 | BN_CTX *bnctx; | ||
2847 | BIGNUM *order, *tmp; | ||
2848 | int ret = SSH_ERR_KEY_INVALID_EC_VALUE; | ||
2849 | |||
2850 | if ((bnctx = BN_CTX_new()) == NULL) | ||
2851 | return SSH_ERR_ALLOC_FAIL; | ||
2852 | BN_CTX_start(bnctx); | ||
2853 | |||
2854 | if ((order = BN_CTX_get(bnctx)) == NULL || | ||
2855 | (tmp = BN_CTX_get(bnctx)) == NULL) { | ||
2856 | ret = SSH_ERR_ALLOC_FAIL; | ||
2857 | goto out; | ||
2858 | } | ||
2859 | |||
2860 | /* log2(private) > log2(order)/2 */ | ||
2861 | if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, bnctx) != 1) { | ||
2862 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
2863 | goto out; | ||
2864 | } | ||
2865 | if (BN_num_bits(EC_KEY_get0_private_key(key)) <= | ||
2866 | BN_num_bits(order) / 2) | ||
2867 | goto out; | ||
2868 | |||
2869 | /* private < order - 1 */ | ||
2870 | if (!BN_sub(tmp, order, BN_value_one())) { | ||
2871 | ret = SSH_ERR_LIBCRYPTO_ERROR; | ||
2872 | goto out; | ||
2873 | } | ||
2874 | if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0) | ||
2875 | goto out; | ||
2876 | ret = 0; | ||
2877 | out: | ||
2878 | BN_CTX_free(bnctx); | ||
2879 | return ret; | ||
2880 | } | ||
2881 | |||
2882 | void | ||
2883 | sshkey_dump_ec_point(const EC_GROUP *group, const EC_POINT *point) | ||
2884 | { | ||
2885 | BIGNUM *x, *y; | ||
2886 | BN_CTX *bnctx; | ||
2887 | |||
2888 | if (point == NULL) { | ||
2889 | fputs("point=(NULL)\n", stderr); | ||
2890 | return; | ||
2891 | } | ||
2892 | if ((bnctx = BN_CTX_new()) == NULL) { | ||
2893 | fprintf(stderr, "%s: BN_CTX_new failed\n", __func__); | ||
2894 | return; | ||
2895 | } | ||
2896 | BN_CTX_start(bnctx); | ||
2897 | if ((x = BN_CTX_get(bnctx)) == NULL || | ||
2898 | (y = BN_CTX_get(bnctx)) == NULL) { | ||
2899 | fprintf(stderr, "%s: BN_CTX_get failed\n", __func__); | ||
2900 | return; | ||
2901 | } | ||
2902 | if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != | ||
2903 | NID_X9_62_prime_field) { | ||
2904 | fprintf(stderr, "%s: group is not a prime field\n", __func__); | ||
2905 | return; | ||
2906 | } | ||
2907 | if (EC_POINT_get_affine_coordinates_GFp(group, point, x, y, | ||
2908 | bnctx) != 1) { | ||
2909 | fprintf(stderr, "%s: EC_POINT_get_affine_coordinates_GFp\n", | ||
2910 | __func__); | ||
2911 | return; | ||
2912 | } | ||
2913 | fputs("x=", stderr); | ||
2914 | BN_print_fp(stderr, x); | ||
2915 | fputs("\ny=", stderr); | ||
2916 | BN_print_fp(stderr, y); | ||
2917 | fputs("\n", stderr); | ||
2918 | BN_CTX_free(bnctx); | ||
2919 | } | ||
2920 | |||
2921 | void | ||
2922 | sshkey_dump_ec_key(const EC_KEY *key) | ||
2923 | { | ||
2924 | const BIGNUM *exponent; | ||
2925 | |||
2926 | sshkey_dump_ec_point(EC_KEY_get0_group(key), | ||
2927 | EC_KEY_get0_public_key(key)); | ||
2928 | fputs("exponent=", stderr); | ||
2929 | if ((exponent = EC_KEY_get0_private_key(key)) == NULL) | ||
2930 | fputs("(NULL)", stderr); | ||
2931 | else | ||
2932 | BN_print_fp(stderr, EC_KEY_get0_private_key(key)); | ||
2933 | fputs("\n", stderr); | ||
2934 | } | ||
2935 | #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ | ||
2936 | |||
2937 | static int | ||
2938 | sshkey_private_to_blob2(const struct sshkey *prv, struct sshbuf *blob, | ||
2939 | const char *passphrase, const char *comment, const char *ciphername, | ||
2940 | int rounds) | ||
2941 | { | ||
2942 | u_char *cp, *b64 = NULL, *key = NULL, *pubkeyblob = NULL; | ||
2943 | u_char salt[SALT_LEN]; | ||
2944 | size_t i, pubkeylen, keylen, ivlen, blocksize, authlen; | ||
2945 | u_int check; | ||
2946 | int r = SSH_ERR_INTERNAL_ERROR; | ||
2947 | struct sshcipher_ctx ciphercontext; | ||
2948 | const struct sshcipher *cipher; | ||
2949 | const char *kdfname = KDFNAME; | ||
2950 | struct sshbuf *encoded = NULL, *encrypted = NULL, *kdf = NULL; | ||
2951 | |||
2952 | memset(&ciphercontext, 0, sizeof(ciphercontext)); | ||
2953 | |||
2954 | if (rounds <= 0) | ||
2955 | rounds = DEFAULT_ROUNDS; | ||
2956 | if (passphrase == NULL || !strlen(passphrase)) { | ||
2957 | ciphername = "none"; | ||
2958 | kdfname = "none"; | ||
2959 | } else if (ciphername == NULL) | ||
2960 | ciphername = DEFAULT_CIPHERNAME; | ||
2961 | else if (cipher_number(ciphername) != SSH_CIPHER_SSH2) { | ||
2962 | r = SSH_ERR_INVALID_ARGUMENT; | ||
2963 | goto out; | ||
2964 | } | ||
2965 | if ((cipher = cipher_by_name(ciphername)) == NULL) { | ||
2966 | r = SSH_ERR_INTERNAL_ERROR; | ||
2967 | goto out; | ||
2968 | } | ||
2969 | |||
2970 | if ((kdf = sshbuf_new()) == NULL || | ||
2971 | (encoded = sshbuf_new()) == NULL || | ||
2972 | (encrypted = sshbuf_new()) == NULL) { | ||
2973 | r = SSH_ERR_ALLOC_FAIL; | ||
2974 | goto out; | ||
2975 | } | ||
2976 | blocksize = cipher_blocksize(cipher); | ||
2977 | keylen = cipher_keylen(cipher); | ||
2978 | ivlen = cipher_ivlen(cipher); | ||
2979 | authlen = cipher_authlen(cipher); | ||
2980 | if ((key = calloc(1, keylen + ivlen)) == NULL) { | ||
2981 | r = SSH_ERR_ALLOC_FAIL; | ||
2982 | goto out; | ||
2983 | } | ||
2984 | if (strcmp(kdfname, "bcrypt") == 0) { | ||
2985 | arc4random_buf(salt, SALT_LEN); | ||
2986 | if (bcrypt_pbkdf(passphrase, strlen(passphrase), | ||
2987 | salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) { | ||
2988 | r = SSH_ERR_INVALID_ARGUMENT; | ||
2989 | goto out; | ||
2990 | } | ||
2991 | if ((r = sshbuf_put_string(kdf, salt, SALT_LEN)) != 0 || | ||
2992 | (r = sshbuf_put_u32(kdf, rounds)) != 0) | ||
2993 | goto out; | ||
2994 | } else if (strcmp(kdfname, "none") != 0) { | ||
2995 | /* Unsupported KDF type */ | ||
2996 | r = SSH_ERR_KEY_UNKNOWN_CIPHER; | ||
2997 | goto out; | ||
2998 | } | ||
2999 | if ((r = cipher_init(&ciphercontext, cipher, key, keylen, | ||
3000 | key + keylen, ivlen, 1)) != 0) | ||
3001 | goto out; | ||
3002 | |||
3003 | if ((r = sshbuf_put(encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC))) != 0 || | ||
3004 | (r = sshbuf_put_cstring(encoded, ciphername)) != 0 || | ||
3005 | (r = sshbuf_put_cstring(encoded, kdfname)) != 0 || | ||
3006 | (r = sshbuf_put_stringb(encoded, kdf)) != 0 || | ||
3007 | (r = sshbuf_put_u32(encoded, 1)) != 0 || /* number of keys */ | ||
3008 | (r = sshkey_to_blob(prv, &pubkeyblob, &pubkeylen)) != 0 || | ||
3009 | (r = sshbuf_put_string(encoded, pubkeyblob, pubkeylen)) != 0) | ||
3010 | goto out; | ||
3011 | |||
3012 | /* set up the buffer that will be encrypted */ | ||
3013 | |||
3014 | /* Random check bytes */ | ||
3015 | check = arc4random(); | ||
3016 | if ((r = sshbuf_put_u32(encrypted, check)) != 0 || | ||
3017 | (r = sshbuf_put_u32(encrypted, check)) != 0) | ||
3018 | goto out; | ||
3019 | |||
3020 | /* append private key and comment*/ | ||
3021 | if ((r = sshkey_private_serialize(prv, encrypted)) != 0 || | ||
3022 | (r = sshbuf_put_cstring(encrypted, comment)) != 0) | ||
3023 | goto out; | ||
3024 | |||
3025 | /* padding */ | ||
3026 | i = 0; | ||
3027 | while (sshbuf_len(encrypted) % blocksize) { | ||
3028 | if ((r = sshbuf_put_u8(encrypted, ++i & 0xff)) != 0) | ||
3029 | goto out; | ||
3030 | } | ||
3031 | |||
3032 | /* length in destination buffer */ | ||
3033 | if ((r = sshbuf_put_u32(encoded, sshbuf_len(encrypted))) != 0) | ||
3034 | goto out; | ||
3035 | |||
3036 | /* encrypt */ | ||
3037 | if ((r = sshbuf_reserve(encoded, | ||
3038 | sshbuf_len(encrypted) + authlen, &cp)) != 0) | ||
3039 | goto out; | ||
3040 | if ((r = cipher_crypt(&ciphercontext, 0, cp, | ||
3041 | sshbuf_ptr(encrypted), sshbuf_len(encrypted), 0, authlen)) != 0) | ||
3042 | goto out; | ||
3043 | |||
3044 | /* uuencode */ | ||
3045 | if ((b64 = sshbuf_dtob64(encoded)) == NULL) { | ||
3046 | r = SSH_ERR_ALLOC_FAIL; | ||
3047 | goto out; | ||
3048 | } | ||
3049 | |||
3050 | sshbuf_reset(blob); | ||
3051 | if ((r = sshbuf_put(blob, MARK_BEGIN, MARK_BEGIN_LEN)) != 0) | ||
3052 | goto out; | ||
3053 | for (i = 0; i < strlen(b64); i++) { | ||
3054 | if ((r = sshbuf_put_u8(blob, b64[i])) != 0) | ||
3055 | goto out; | ||
3056 | /* insert line breaks */ | ||
3057 | if (i % 70 == 69 && (r = sshbuf_put_u8(blob, '\n')) != 0) | ||
3058 | goto out; | ||
3059 | } | ||
3060 | if (i % 70 != 69 && (r = sshbuf_put_u8(blob, '\n')) != 0) | ||
3061 | goto out; | ||
3062 | if ((r = sshbuf_put(blob, MARK_END, MARK_END_LEN)) != 0) | ||
3063 | goto out; | ||
3064 | |||
3065 | /* success */ | ||
3066 | r = 0; | ||
3067 | |||
3068 | out: | ||
3069 | sshbuf_free(kdf); | ||
3070 | sshbuf_free(encoded); | ||
3071 | sshbuf_free(encrypted); | ||
3072 | cipher_cleanup(&ciphercontext); | ||
3073 | explicit_bzero(salt, sizeof(salt)); | ||
3074 | if (key != NULL) { | ||
3075 | explicit_bzero(key, keylen + ivlen); | ||
3076 | free(key); | ||
3077 | } | ||
3078 | if (pubkeyblob != NULL) { | ||
3079 | explicit_bzero(pubkeyblob, pubkeylen); | ||
3080 | free(pubkeyblob); | ||
3081 | } | ||
3082 | if (b64 != NULL) { | ||
3083 | explicit_bzero(b64, strlen(b64)); | ||
3084 | free(b64); | ||
3085 | } | ||
3086 | return r; | ||
3087 | } | ||
3088 | |||
3089 | static int | ||
3090 | sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, | ||
3091 | struct sshkey **keyp, char **commentp) | ||
3092 | { | ||
3093 | char *comment = NULL, *ciphername = NULL, *kdfname = NULL; | ||
3094 | const struct sshcipher *cipher = NULL; | ||
3095 | const u_char *cp; | ||
3096 | int r = SSH_ERR_INTERNAL_ERROR; | ||
3097 | size_t encoded_len; | ||
3098 | size_t i, keylen = 0, ivlen = 0, slen = 0; | ||
3099 | struct sshbuf *encoded = NULL, *decoded = NULL; | ||
3100 | struct sshbuf *kdf = NULL, *decrypted = NULL; | ||
3101 | struct sshcipher_ctx ciphercontext; | ||
3102 | struct sshkey *k = NULL; | ||
3103 | u_char *key = NULL, *salt = NULL, *dp, pad, last; | ||
3104 | u_int blocksize, rounds, nkeys, encrypted_len, check1, check2; | ||
3105 | |||
3106 | memset(&ciphercontext, 0, sizeof(ciphercontext)); | ||
3107 | if (keyp != NULL) | ||
3108 | *keyp = NULL; | ||
3109 | if (commentp != NULL) | ||
3110 | *commentp = NULL; | ||
3111 | |||
3112 | if ((encoded = sshbuf_new()) == NULL || | ||
3113 | (decoded = sshbuf_new()) == NULL || | ||
3114 | (decrypted = sshbuf_new()) == NULL) { | ||
3115 | r = SSH_ERR_ALLOC_FAIL; | ||
3116 | goto out; | ||
3117 | } | ||
3118 | |||
3119 | /* check preamble */ | ||
3120 | cp = sshbuf_ptr(blob); | ||
3121 | encoded_len = sshbuf_len(blob); | ||
3122 | if (encoded_len < (MARK_BEGIN_LEN + MARK_END_LEN) || | ||
3123 | memcmp(cp, MARK_BEGIN, MARK_BEGIN_LEN) != 0) { | ||
3124 | r = SSH_ERR_INVALID_FORMAT; | ||
3125 | goto out; | ||
3126 | } | ||
3127 | cp += MARK_BEGIN_LEN; | ||
3128 | encoded_len -= MARK_BEGIN_LEN; | ||
3129 | |||
3130 | /* Look for end marker, removing whitespace as we go */ | ||
3131 | while (encoded_len > 0) { | ||
3132 | if (*cp != '\n' && *cp != '\r') { | ||
3133 | if ((r = sshbuf_put_u8(encoded, *cp)) != 0) | ||
3134 | goto out; | ||
3135 | } | ||
3136 | last = *cp; | ||
3137 | encoded_len--; | ||
3138 | cp++; | ||
3139 | if (last == '\n') { | ||
3140 | if (encoded_len >= MARK_END_LEN && | ||
3141 | memcmp(cp, MARK_END, MARK_END_LEN) == 0) { | ||
3142 | /* \0 terminate */ | ||
3143 | if ((r = sshbuf_put_u8(encoded, 0)) != 0) | ||
3144 | goto out; | ||
3145 | break; | ||
3146 | } | ||
3147 | } | ||
3148 | } | ||
3149 | if (encoded_len == 0) { | ||
3150 | r = SSH_ERR_INVALID_FORMAT; | ||
3151 | goto out; | ||
3152 | } | ||
3153 | |||
3154 | /* decode base64 */ | ||
3155 | if ((r = sshbuf_b64tod(decoded, sshbuf_ptr(encoded))) != 0) | ||
3156 | goto out; | ||
3157 | |||
3158 | /* check magic */ | ||
3159 | if (sshbuf_len(decoded) < sizeof(AUTH_MAGIC) || | ||
3160 | memcmp(sshbuf_ptr(decoded), AUTH_MAGIC, sizeof(AUTH_MAGIC))) { | ||
3161 | r = SSH_ERR_INVALID_FORMAT; | ||
3162 | goto out; | ||
3163 | } | ||
3164 | /* parse public portion of key */ | ||
3165 | if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 || | ||
3166 | (r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 || | ||
3167 | (r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 || | ||
3168 | (r = sshbuf_froms(decoded, &kdf)) != 0 || | ||
3169 | (r = sshbuf_get_u32(decoded, &nkeys)) != 0 || | ||
3170 | (r = sshbuf_skip_string(decoded)) != 0 || /* pubkey */ | ||
3171 | (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0) | ||
3172 | goto out; | ||
3173 | |||
3174 | if ((cipher = cipher_by_name(ciphername)) == NULL) { | ||
3175 | r = SSH_ERR_KEY_UNKNOWN_CIPHER; | ||
3176 | goto out; | ||
3177 | } | ||
3178 | if ((passphrase == NULL || strlen(passphrase) == 0) && | ||
3179 | strcmp(ciphername, "none") != 0) { | ||
3180 | /* passphrase required */ | ||
3181 | r = SSH_ERR_KEY_WRONG_PASSPHRASE; | ||
3182 | goto out; | ||
3183 | } | ||
3184 | if (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0) { | ||
3185 | r = SSH_ERR_KEY_UNKNOWN_CIPHER; | ||
3186 | goto out; | ||
3187 | } | ||
3188 | if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) { | ||
3189 | r = SSH_ERR_INVALID_FORMAT; | ||
3190 | goto out; | ||
3191 | } | ||
3192 | if (nkeys != 1) { | ||
3193 | /* XXX only one key supported */ | ||
3194 | r = SSH_ERR_INVALID_FORMAT; | ||
3195 | goto out; | ||
3196 | } | ||
3197 | |||
3198 | /* check size of encrypted key blob */ | ||
3199 | blocksize = cipher_blocksize(cipher); | ||
3200 | if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) { | ||
3201 | r = SSH_ERR_INVALID_FORMAT; | ||
3202 | goto out; | ||
3203 | } | ||
3204 | |||
3205 | /* setup key */ | ||
3206 | keylen = cipher_keylen(cipher); | ||
3207 | ivlen = cipher_ivlen(cipher); | ||
3208 | if ((key = calloc(1, keylen + ivlen)) == NULL) { | ||
3209 | r = SSH_ERR_ALLOC_FAIL; | ||
3210 | goto out; | ||
3211 | } | ||
3212 | if (strcmp(kdfname, "bcrypt") == 0) { | ||
3213 | if ((r = sshbuf_get_string(kdf, &salt, &slen)) != 0 || | ||
3214 | (r = sshbuf_get_u32(kdf, &rounds)) != 0) | ||
3215 | goto out; | ||
3216 | if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen, | ||
3217 | key, keylen + ivlen, rounds) < 0) { | ||
3218 | r = SSH_ERR_INVALID_FORMAT; | ||
3219 | goto out; | ||
3220 | } | ||
3221 | } | ||
3222 | |||
3223 | /* decrypt private portion of key */ | ||
3224 | if ((r = sshbuf_reserve(decrypted, encrypted_len, &dp)) != 0 || | ||
3225 | (r = cipher_init(&ciphercontext, cipher, key, keylen, | ||
3226 | key + keylen, ivlen, 0)) != 0) | ||
3227 | goto out; | ||
3228 | if ((r = cipher_crypt(&ciphercontext, 0, dp, sshbuf_ptr(decoded), | ||
3229 | sshbuf_len(decoded), 0, cipher_authlen(cipher))) != 0) { | ||
3230 | /* an integrity error here indicates an incorrect passphrase */ | ||
3231 | if (r == SSH_ERR_MAC_INVALID) | ||
3232 | r = SSH_ERR_KEY_WRONG_PASSPHRASE; | ||
3233 | goto out; | ||
3234 | } | ||
3235 | if ((r = sshbuf_consume(decoded, encrypted_len)) != 0) | ||
3236 | goto out; | ||
3237 | /* there should be no trailing data */ | ||
3238 | if (sshbuf_len(decoded) != 0) { | ||
3239 | r = SSH_ERR_INVALID_FORMAT; | ||
3240 | goto out; | ||
3241 | } | ||
3242 | |||
3243 | /* check check bytes */ | ||
3244 | if ((r = sshbuf_get_u32(decrypted, &check1)) != 0 || | ||
3245 | (r = sshbuf_get_u32(decrypted, &check2)) != 0) | ||
3246 | goto out; | ||
3247 | if (check1 != check2) { | ||
3248 | r = SSH_ERR_KEY_WRONG_PASSPHRASE; | ||
3249 | goto out; | ||
3250 | } | ||
3251 | |||
3252 | /* Load the private key and comment */ | ||
3253 | if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 || | ||
3254 | (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0) | ||
3255 | goto out; | ||
3256 | |||
3257 | /* Check deterministic padding */ | ||
3258 | i = 0; | ||
3259 | while (sshbuf_len(decrypted)) { | ||
3260 | if ((r = sshbuf_get_u8(decrypted, &pad)) != 0) | ||
3261 | goto out; | ||
3262 | if (pad != (++i & 0xff)) { | ||
3263 | r = SSH_ERR_INVALID_FORMAT; | ||
3264 | goto out; | ||
3265 | } | ||
3266 | } | ||
3267 | |||
3268 | /* XXX decode pubkey and check against private */ | ||
3269 | |||
3270 | /* success */ | ||
3271 | r = 0; | ||
3272 | if (keyp != NULL) { | ||
3273 | *keyp = k; | ||
3274 | k = NULL; | ||
3275 | } | ||
3276 | if (commentp != NULL) { | ||
3277 | *commentp = comment; | ||
3278 | comment = NULL; | ||
3279 | } | ||
3280 | out: | ||
3281 | pad = 0; | ||
3282 | cipher_cleanup(&ciphercontext); | ||
3283 | free(ciphername); | ||
3284 | free(kdfname); | ||
3285 | free(comment); | ||
3286 | if (salt != NULL) { | ||
3287 | explicit_bzero(salt, slen); | ||
3288 | free(salt); | ||
3289 | } | ||
3290 | if (key != NULL) { | ||
3291 | explicit_bzero(key, keylen + ivlen); | ||
3292 | free(key); | ||
3293 | } | ||
3294 | sshbuf_free(encoded); | ||
3295 | sshbuf_free(decoded); | ||
3296 | sshbuf_free(kdf); | ||
3297 | sshbuf_free(decrypted); | ||
3298 | sshkey_free(k); | ||
3299 | return r; | ||
3300 | } | ||
3301 | |||
3302 | #if WITH_SSH1 | ||
3303 | /* | ||
3304 | * Serialises the authentication (private) key to a blob, encrypting it with | ||
3305 | * passphrase. The identification of the blob (lowest 64 bits of n) will | ||
3306 | * precede the key to provide identification of the key without needing a | ||
3307 | * passphrase. | ||
3308 | */ | ||
3309 | static int | ||
3310 | sshkey_private_rsa1_to_blob(struct sshkey *key, struct sshbuf *blob, | ||
3311 | const char *passphrase, const char *comment) | ||
3312 | { | ||
3313 | struct sshbuf *buffer = NULL, *encrypted = NULL; | ||
3314 | u_char buf[8]; | ||
3315 | int r, cipher_num; | ||
3316 | struct sshcipher_ctx ciphercontext; | ||
3317 | const struct sshcipher *cipher; | ||
3318 | u_char *cp; | ||
3319 | |||
3320 | /* | ||
3321 | * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting | ||
3322 | * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. | ||
3323 | */ | ||
3324 | cipher_num = (strcmp(passphrase, "") == 0) ? | ||
3325 | SSH_CIPHER_NONE : SSH_CIPHER_3DES; | ||
3326 | if ((cipher = cipher_by_number(cipher_num)) == NULL) | ||
3327 | return SSH_ERR_INTERNAL_ERROR; | ||
3328 | |||
3329 | /* This buffer is used to build the secret part of the private key. */ | ||
3330 | if ((buffer = sshbuf_new()) == NULL) | ||
3331 | return SSH_ERR_ALLOC_FAIL; | ||
3332 | |||
3333 | /* Put checkbytes for checking passphrase validity. */ | ||
3334 | if ((r = sshbuf_reserve(buffer, 4, &cp)) != 0) | ||
3335 | goto out; | ||
3336 | arc4random_buf(cp, 2); | ||
3337 | memcpy(cp + 2, cp, 2); | ||
3338 | |||
3339 | /* | ||
3340 | * Store the private key (n and e will not be stored because they | ||
3341 | * will be stored in plain text, and storing them also in encrypted | ||
3342 | * format would just give known plaintext). | ||
3343 | * Note: q and p are stored in reverse order to SSL. | ||
3344 | */ | ||
3345 | if ((r = sshbuf_put_bignum1(buffer, key->rsa->d)) != 0 || | ||
3346 | (r = sshbuf_put_bignum1(buffer, key->rsa->iqmp)) != 0 || | ||
3347 | (r = sshbuf_put_bignum1(buffer, key->rsa->q)) != 0 || | ||
3348 | (r = sshbuf_put_bignum1(buffer, key->rsa->p)) != 0) | ||
3349 | goto out; | ||
3350 | |||
3351 | /* Pad the part to be encrypted to a size that is a multiple of 8. */ | ||
3352 | explicit_bzero(buf, 8); | ||
3353 | if ((r = sshbuf_put(buffer, buf, 8 - (sshbuf_len(buffer) % 8))) != 0) | ||
3354 | goto out; | ||
3355 | |||
3356 | /* This buffer will be used to contain the data in the file. */ | ||
3357 | if ((encrypted = sshbuf_new()) == NULL) { | ||
3358 | r = SSH_ERR_ALLOC_FAIL; | ||
3359 | goto out; | ||
3360 | } | ||
3361 | |||
3362 | /* First store keyfile id string. */ | ||
3363 | if ((r = sshbuf_put(encrypted, LEGACY_BEGIN, | ||
3364 | sizeof(LEGACY_BEGIN))) != 0) | ||
3365 | goto out; | ||
3366 | |||
3367 | /* Store cipher type and "reserved" field. */ | ||
3368 | if ((r = sshbuf_put_u8(encrypted, cipher_num)) != 0 || | ||
3369 | (r = sshbuf_put_u32(encrypted, 0)) != 0) | ||
3370 | goto out; | ||
3371 | |||
3372 | /* Store public key. This will be in plain text. */ | ||
3373 | if ((r = sshbuf_put_u32(encrypted, BN_num_bits(key->rsa->n))) != 0 || | ||
3374 | (r = sshbuf_put_bignum1(encrypted, key->rsa->n) != 0) || | ||
3375 | (r = sshbuf_put_bignum1(encrypted, key->rsa->e) != 0) || | ||
3376 | (r = sshbuf_put_cstring(encrypted, comment) != 0)) | ||
3377 | goto out; | ||
3378 | |||
3379 | /* Allocate space for the private part of the key in the buffer. */ | ||
3380 | if ((r = sshbuf_reserve(encrypted, sshbuf_len(buffer), &cp)) != 0) | ||
3381 | goto out; | ||
3382 | |||
3383 | if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase, | ||
3384 | CIPHER_ENCRYPT)) != 0) | ||
3385 | goto out; | ||
3386 | if ((r = cipher_crypt(&ciphercontext, 0, cp, | ||
3387 | sshbuf_ptr(buffer), sshbuf_len(buffer), 0, 0)) != 0) | ||
3388 | goto out; | ||
3389 | if ((r = cipher_cleanup(&ciphercontext)) != 0) | ||
3390 | goto out; | ||
3391 | |||
3392 | r = sshbuf_putb(blob, encrypted); | ||
3393 | |||
3394 | out: | ||
3395 | explicit_bzero(&ciphercontext, sizeof(ciphercontext)); | ||
3396 | explicit_bzero(buf, sizeof(buf)); | ||
3397 | if (buffer != NULL) | ||
3398 | sshbuf_free(buffer); | ||
3399 | if (encrypted != NULL) | ||
3400 | sshbuf_free(encrypted); | ||
3401 | |||
3402 | return r; | ||
3403 | } | ||
3404 | #endif /* WITH_SSH1 */ | ||
3405 | |||
3406 | #ifdef WITH_OPENSSL | ||
3407 | /* convert SSH v2 key in OpenSSL PEM format */ | ||
3408 | static int | ||
3409 | sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *blob, | ||
3410 | const char *_passphrase, const char *comment) | ||
3411 | { | ||
3412 | int success, r; | ||
3413 | int blen, len = strlen(_passphrase); | ||
3414 | u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; | ||
3415 | #if (OPENSSL_VERSION_NUMBER < 0x00907000L) | ||
3416 | const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; | ||
3417 | #else | ||
3418 | const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; | ||
3419 | #endif | ||
3420 | const u_char *bptr; | ||
3421 | BIO *bio = NULL; | ||
3422 | |||
3423 | if (len > 0 && len <= 4) | ||
3424 | return SSH_ERR_PASSPHRASE_TOO_SHORT; | ||
3425 | if ((bio = BIO_new(BIO_s_mem())) == NULL) | ||
3426 | return SSH_ERR_ALLOC_FAIL; | ||
3427 | |||
3428 | switch (key->type) { | ||
3429 | case KEY_DSA: | ||
3430 | success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, | ||
3431 | cipher, passphrase, len, NULL, NULL); | ||
3432 | break; | ||
3433 | #ifdef OPENSSL_HAS_ECC | ||
3434 | case KEY_ECDSA: | ||
3435 | success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, | ||
3436 | cipher, passphrase, len, NULL, NULL); | ||
3437 | break; | ||
3438 | #endif | ||
3439 | case KEY_RSA: | ||
3440 | success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, | ||
3441 | cipher, passphrase, len, NULL, NULL); | ||
3442 | break; | ||
3443 | default: | ||
3444 | success = 0; | ||
3445 | break; | ||
3446 | } | ||
3447 | if (success == 0) { | ||
3448 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
3449 | goto out; | ||
3450 | } | ||
3451 | if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) { | ||
3452 | r = SSH_ERR_INTERNAL_ERROR; | ||
3453 | goto out; | ||
3454 | } | ||
3455 | if ((r = sshbuf_put(blob, bptr, blen)) != 0) | ||
3456 | goto out; | ||
3457 | r = 0; | ||
3458 | out: | ||
3459 | BIO_free(bio); | ||
3460 | return r; | ||
3461 | } | ||
3462 | #endif /* WITH_OPENSSL */ | ||
3463 | |||
3464 | /* Serialise "key" to buffer "blob" */ | ||
3465 | int | ||
3466 | sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob, | ||
3467 | const char *passphrase, const char *comment, | ||
3468 | int force_new_format, const char *new_format_cipher, int new_format_rounds) | ||
3469 | { | ||
3470 | switch (key->type) { | ||
3471 | #ifdef WITH_OPENSSL | ||
3472 | case KEY_RSA1: | ||
3473 | return sshkey_private_rsa1_to_blob(key, blob, | ||
3474 | passphrase, comment); | ||
3475 | case KEY_DSA: | ||
3476 | case KEY_ECDSA: | ||
3477 | case KEY_RSA: | ||
3478 | if (force_new_format) { | ||
3479 | return sshkey_private_to_blob2(key, blob, passphrase, | ||
3480 | comment, new_format_cipher, new_format_rounds); | ||
3481 | } | ||
3482 | return sshkey_private_pem_to_blob(key, blob, | ||
3483 | passphrase, comment); | ||
3484 | #endif /* WITH_OPENSSL */ | ||
3485 | case KEY_ED25519: | ||
3486 | return sshkey_private_to_blob2(key, blob, passphrase, | ||
3487 | comment, new_format_cipher, new_format_rounds); | ||
3488 | default: | ||
3489 | return SSH_ERR_KEY_TYPE_UNKNOWN; | ||
3490 | } | ||
3491 | } | ||
3492 | |||
3493 | #ifdef WITH_SSH1 | ||
3494 | /* | ||
3495 | * Parse the public, unencrypted portion of a RSA1 key. | ||
3496 | */ | ||
3497 | int | ||
3498 | sshkey_parse_public_rsa1_fileblob(struct sshbuf *blob, | ||
3499 | struct sshkey **keyp, char **commentp) | ||
3500 | { | ||
3501 | int r; | ||
3502 | struct sshkey *pub = NULL; | ||
3503 | struct sshbuf *copy = NULL; | ||
3504 | |||
3505 | if (keyp != NULL) | ||
3506 | *keyp = NULL; | ||
3507 | if (commentp != NULL) | ||
3508 | *commentp = NULL; | ||
3509 | |||
3510 | /* Check that it is at least big enough to contain the ID string. */ | ||
3511 | if (sshbuf_len(blob) < sizeof(LEGACY_BEGIN)) | ||
3512 | return SSH_ERR_INVALID_FORMAT; | ||
3513 | |||
3514 | /* | ||
3515 | * Make sure it begins with the id string. Consume the id string | ||
3516 | * from the buffer. | ||
3517 | */ | ||
3518 | if (memcmp(sshbuf_ptr(blob), LEGACY_BEGIN, sizeof(LEGACY_BEGIN)) != 0) | ||
3519 | return SSH_ERR_INVALID_FORMAT; | ||
3520 | /* Make a working copy of the keyblob and skip past the magic */ | ||
3521 | if ((copy = sshbuf_fromb(blob)) == NULL) | ||
3522 | return SSH_ERR_ALLOC_FAIL; | ||
3523 | if ((r = sshbuf_consume(copy, sizeof(LEGACY_BEGIN))) != 0) | ||
3524 | goto out; | ||
3525 | |||
3526 | /* Skip cipher type, reserved data and key bits. */ | ||
3527 | if ((r = sshbuf_get_u8(copy, NULL)) != 0 || /* cipher type */ | ||
3528 | (r = sshbuf_get_u32(copy, NULL)) != 0 || /* reserved */ | ||
3529 | (r = sshbuf_get_u32(copy, NULL)) != 0) /* key bits */ | ||
3530 | goto out; | ||
3531 | |||
3532 | /* Read the public key from the buffer. */ | ||
3533 | if ((pub = sshkey_new(KEY_RSA1)) == NULL || | ||
3534 | (r = sshbuf_get_bignum1(copy, pub->rsa->n)) != 0 || | ||
3535 | (r = sshbuf_get_bignum1(copy, pub->rsa->e)) != 0) | ||
3536 | goto out; | ||
3537 | |||
3538 | /* Finally, the comment */ | ||
3539 | if ((r = sshbuf_get_string(copy, (u_char**)commentp, NULL)) != 0) | ||
3540 | goto out; | ||
3541 | |||
3542 | /* The encrypted private part is not parsed by this function. */ | ||
3543 | |||
3544 | r = 0; | ||
3545 | if (keyp != NULL) | ||
3546 | *keyp = pub; | ||
3547 | else | ||
3548 | sshkey_free(pub); | ||
3549 | pub = NULL; | ||
3550 | |||
3551 | out: | ||
3552 | if (copy != NULL) | ||
3553 | sshbuf_free(copy); | ||
3554 | if (pub != NULL) | ||
3555 | sshkey_free(pub); | ||
3556 | return r; | ||
3557 | } | ||
3558 | |||
3559 | static int | ||
3560 | sshkey_parse_private_rsa1(struct sshbuf *blob, const char *passphrase, | ||
3561 | struct sshkey **keyp, char **commentp) | ||
3562 | { | ||
3563 | int r; | ||
3564 | u_int16_t check1, check2; | ||
3565 | u_int8_t cipher_type; | ||
3566 | struct sshbuf *decrypted = NULL, *copy = NULL; | ||
3567 | u_char *cp; | ||
3568 | char *comment = NULL; | ||
3569 | struct sshcipher_ctx ciphercontext; | ||
3570 | const struct sshcipher *cipher; | ||
3571 | struct sshkey *prv = NULL; | ||
3572 | |||
3573 | *keyp = NULL; | ||
3574 | if (commentp != NULL) | ||
3575 | *commentp = NULL; | ||
3576 | |||
3577 | /* Check that it is at least big enough to contain the ID string. */ | ||
3578 | if (sshbuf_len(blob) < sizeof(LEGACY_BEGIN)) | ||
3579 | return SSH_ERR_INVALID_FORMAT; | ||
3580 | |||
3581 | /* | ||
3582 | * Make sure it begins with the id string. Consume the id string | ||
3583 | * from the buffer. | ||
3584 | */ | ||
3585 | if (memcmp(sshbuf_ptr(blob), LEGACY_BEGIN, sizeof(LEGACY_BEGIN)) != 0) | ||
3586 | return SSH_ERR_INVALID_FORMAT; | ||
3587 | |||
3588 | if ((prv = sshkey_new_private(KEY_RSA1)) == NULL) { | ||
3589 | r = SSH_ERR_ALLOC_FAIL; | ||
3590 | goto out; | ||
3591 | } | ||
3592 | if ((copy = sshbuf_fromb(blob)) == NULL || | ||
3593 | (decrypted = sshbuf_new()) == NULL) { | ||
3594 | r = SSH_ERR_ALLOC_FAIL; | ||
3595 | goto out; | ||
3596 | } | ||
3597 | if ((r = sshbuf_consume(copy, sizeof(LEGACY_BEGIN))) != 0) | ||
3598 | goto out; | ||
3599 | |||
3600 | /* Read cipher type. */ | ||
3601 | if ((r = sshbuf_get_u8(copy, &cipher_type)) != 0 || | ||
3602 | (r = sshbuf_get_u32(copy, NULL)) != 0) /* reserved */ | ||
3603 | goto out; | ||
3604 | |||
3605 | /* Read the public key and comment from the buffer. */ | ||
3606 | if ((r = sshbuf_get_u32(copy, NULL)) != 0 || /* key bits */ | ||
3607 | (r = sshbuf_get_bignum1(copy, prv->rsa->n)) != 0 || | ||
3608 | (r = sshbuf_get_bignum1(copy, prv->rsa->e)) != 0 || | ||
3609 | (r = sshbuf_get_cstring(copy, &comment, NULL)) != 0) | ||
3610 | goto out; | ||
3611 | |||
3612 | /* Check that it is a supported cipher. */ | ||
3613 | cipher = cipher_by_number(cipher_type); | ||
3614 | if (cipher == NULL) { | ||
3615 | r = SSH_ERR_KEY_UNKNOWN_CIPHER; | ||
3616 | goto out; | ||
3617 | } | ||
3618 | /* Initialize space for decrypted data. */ | ||
3619 | if ((r = sshbuf_reserve(decrypted, sshbuf_len(copy), &cp)) != 0) | ||
3620 | goto out; | ||
3621 | |||
3622 | /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ | ||
3623 | if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase, | ||
3624 | CIPHER_DECRYPT)) != 0) | ||
3625 | goto out; | ||
3626 | if ((r = cipher_crypt(&ciphercontext, 0, cp, | ||
3627 | sshbuf_ptr(copy), sshbuf_len(copy), 0, 0)) != 0) { | ||
3628 | cipher_cleanup(&ciphercontext); | ||
3629 | goto out; | ||
3630 | } | ||
3631 | if ((r = cipher_cleanup(&ciphercontext)) != 0) | ||
3632 | goto out; | ||
3633 | |||
3634 | if ((r = sshbuf_get_u16(decrypted, &check1)) != 0 || | ||
3635 | (r = sshbuf_get_u16(decrypted, &check2)) != 0) | ||
3636 | goto out; | ||
3637 | if (check1 != check2) { | ||
3638 | r = SSH_ERR_KEY_WRONG_PASSPHRASE; | ||
3639 | goto out; | ||
3640 | } | ||
3641 | |||
3642 | /* Read the rest of the private key. */ | ||
3643 | if ((r = sshbuf_get_bignum1(decrypted, prv->rsa->d)) != 0 || | ||
3644 | (r = sshbuf_get_bignum1(decrypted, prv->rsa->iqmp)) != 0 || | ||
3645 | (r = sshbuf_get_bignum1(decrypted, prv->rsa->q)) != 0 || | ||
3646 | (r = sshbuf_get_bignum1(decrypted, prv->rsa->p)) != 0) | ||
3647 | goto out; | ||
3648 | |||
3649 | /* calculate p-1 and q-1 */ | ||
3650 | if ((r = rsa_generate_additional_parameters(prv->rsa)) != 0) | ||
3651 | goto out; | ||
3652 | |||
3653 | /* enable blinding */ | ||
3654 | if (RSA_blinding_on(prv->rsa, NULL) != 1) { | ||
3655 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
3656 | goto out; | ||
3657 | } | ||
3658 | r = 0; | ||
3659 | *keyp = prv; | ||
3660 | prv = NULL; | ||
3661 | if (commentp != NULL) { | ||
3662 | *commentp = comment; | ||
3663 | comment = NULL; | ||
3664 | } | ||
3665 | out: | ||
3666 | explicit_bzero(&ciphercontext, sizeof(ciphercontext)); | ||
3667 | if (comment != NULL) | ||
3668 | free(comment); | ||
3669 | if (prv != NULL) | ||
3670 | sshkey_free(prv); | ||
3671 | if (copy != NULL) | ||
3672 | sshbuf_free(copy); | ||
3673 | if (decrypted != NULL) | ||
3674 | sshbuf_free(decrypted); | ||
3675 | return r; | ||
3676 | } | ||
3677 | #endif /* WITH_SSH1 */ | ||
3678 | |||
3679 | #ifdef WITH_OPENSSL | ||
3680 | /* XXX make private once ssh-keysign.c fixed */ | ||
3681 | int | ||
3682 | sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, | ||
3683 | const char *passphrase, struct sshkey **keyp, char **commentp) | ||
3684 | { | ||
3685 | EVP_PKEY *pk = NULL; | ||
3686 | struct sshkey *prv = NULL; | ||
3687 | char *name = "<no key>"; | ||
3688 | BIO *bio = NULL; | ||
3689 | int r; | ||
3690 | |||
3691 | *keyp = NULL; | ||
3692 | if (commentp != NULL) | ||
3693 | *commentp = NULL; | ||
3694 | |||
3695 | if ((bio = BIO_new(BIO_s_mem())) == NULL || sshbuf_len(blob) > INT_MAX) | ||
3696 | return SSH_ERR_ALLOC_FAIL; | ||
3697 | if (BIO_write(bio, sshbuf_ptr(blob), sshbuf_len(blob)) != | ||
3698 | (int)sshbuf_len(blob)) { | ||
3699 | r = SSH_ERR_ALLOC_FAIL; | ||
3700 | goto out; | ||
3701 | } | ||
3702 | |||
3703 | if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, | ||
3704 | (char *)passphrase)) == NULL) { | ||
3705 | r = SSH_ERR_KEY_WRONG_PASSPHRASE; | ||
3706 | goto out; | ||
3707 | } | ||
3708 | if (pk->type == EVP_PKEY_RSA && | ||
3709 | (type == KEY_UNSPEC || type == KEY_RSA)) { | ||
3710 | if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) { | ||
3711 | r = SSH_ERR_ALLOC_FAIL; | ||
3712 | goto out; | ||
3713 | } | ||
3714 | prv->rsa = EVP_PKEY_get1_RSA(pk); | ||
3715 | prv->type = KEY_RSA; | ||
3716 | name = "rsa w/o comment"; | ||
3717 | #ifdef DEBUG_PK | ||
3718 | RSA_print_fp(stderr, prv->rsa, 8); | ||
3719 | #endif | ||
3720 | if (RSA_blinding_on(prv->rsa, NULL) != 1) { | ||
3721 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
3722 | goto out; | ||
3723 | } | ||
3724 | } else if (pk->type == EVP_PKEY_DSA && | ||
3725 | (type == KEY_UNSPEC || type == KEY_DSA)) { | ||
3726 | if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) { | ||
3727 | r = SSH_ERR_ALLOC_FAIL; | ||
3728 | goto out; | ||
3729 | } | ||
3730 | prv->dsa = EVP_PKEY_get1_DSA(pk); | ||
3731 | prv->type = KEY_DSA; | ||
3732 | name = "dsa w/o comment"; | ||
3733 | #ifdef DEBUG_PK | ||
3734 | DSA_print_fp(stderr, prv->dsa, 8); | ||
3735 | #endif | ||
3736 | #ifdef OPENSSL_HAS_ECC | ||
3737 | } else if (pk->type == EVP_PKEY_EC && | ||
3738 | (type == KEY_UNSPEC || type == KEY_ECDSA)) { | ||
3739 | if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) { | ||
3740 | r = SSH_ERR_ALLOC_FAIL; | ||
3741 | goto out; | ||
3742 | } | ||
3743 | prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk); | ||
3744 | prv->type = KEY_ECDSA; | ||
3745 | prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->ecdsa); | ||
3746 | if (prv->ecdsa_nid == -1 || | ||
3747 | sshkey_curve_nid_to_name(prv->ecdsa_nid) == NULL || | ||
3748 | sshkey_ec_validate_public(EC_KEY_get0_group(prv->ecdsa), | ||
3749 | EC_KEY_get0_public_key(prv->ecdsa)) != 0 || | ||
3750 | sshkey_ec_validate_private(prv->ecdsa) != 0) { | ||
3751 | r = SSH_ERR_INVALID_FORMAT; | ||
3752 | goto out; | ||
3753 | } | ||
3754 | name = "ecdsa w/o comment"; | ||
3755 | # ifdef DEBUG_PK | ||
3756 | if (prv != NULL && prv->ecdsa != NULL) | ||
3757 | sshkey_dump_ec_key(prv->ecdsa); | ||
3758 | # endif | ||
3759 | #endif /* OPENSSL_HAS_ECC */ | ||
3760 | } else { | ||
3761 | r = SSH_ERR_INVALID_FORMAT; | ||
3762 | goto out; | ||
3763 | } | ||
3764 | if (commentp != NULL && | ||
3765 | (*commentp = strdup(name)) == NULL) { | ||
3766 | r = SSH_ERR_ALLOC_FAIL; | ||
3767 | goto out; | ||
3768 | } | ||
3769 | r = 0; | ||
3770 | *keyp = prv; | ||
3771 | prv = NULL; | ||
3772 | out: | ||
3773 | BIO_free(bio); | ||
3774 | if (pk != NULL) | ||
3775 | EVP_PKEY_free(pk); | ||
3776 | if (prv != NULL) | ||
3777 | sshkey_free(prv); | ||
3778 | return r; | ||
3779 | } | ||
3780 | #endif /* WITH_OPENSSL */ | ||
3781 | |||
3782 | int | ||
3783 | sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type, | ||
3784 | const char *passphrase, struct sshkey **keyp, char **commentp) | ||
3785 | { | ||
3786 | int r; | ||
3787 | |||
3788 | *keyp = NULL; | ||
3789 | if (commentp != NULL) | ||
3790 | *commentp = NULL; | ||
3791 | |||
3792 | switch (type) { | ||
3793 | #ifdef WITH_OPENSSL | ||
3794 | case KEY_RSA1: | ||
3795 | return sshkey_parse_private_rsa1(blob, passphrase, | ||
3796 | keyp, commentp); | ||
3797 | case KEY_DSA: | ||
3798 | case KEY_ECDSA: | ||
3799 | case KEY_RSA: | ||
3800 | return sshkey_parse_private_pem_fileblob(blob, type, passphrase, | ||
3801 | keyp, commentp); | ||
3802 | #endif /* WITH_OPENSSL */ | ||
3803 | case KEY_ED25519: | ||
3804 | return sshkey_parse_private2(blob, type, passphrase, | ||
3805 | keyp, commentp); | ||
3806 | case KEY_UNSPEC: | ||
3807 | if ((r = sshkey_parse_private2(blob, type, passphrase, keyp, | ||
3808 | commentp)) == 0) | ||
3809 | return 0; | ||
3810 | #ifdef WITH_OPENSSL | ||
3811 | return sshkey_parse_private_pem_fileblob(blob, type, passphrase, | ||
3812 | keyp, commentp); | ||
3813 | #else | ||
3814 | return SSH_ERR_INVALID_FORMAT; | ||
3815 | #endif /* WITH_OPENSSL */ | ||
3816 | default: | ||
3817 | return SSH_ERR_KEY_TYPE_UNKNOWN; | ||
3818 | } | ||
3819 | } | ||
3820 | |||
3821 | int | ||
3822 | sshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase, | ||
3823 | const char *filename, struct sshkey **keyp, char **commentp) | ||
3824 | { | ||
3825 | int r; | ||
3826 | |||
3827 | if (keyp != NULL) | ||
3828 | *keyp = NULL; | ||
3829 | if (commentp != NULL) | ||
3830 | *commentp = NULL; | ||
3831 | |||
3832 | #ifdef WITH_SSH1 | ||
3833 | /* it's a SSH v1 key if the public key part is readable */ | ||
3834 | if ((r = sshkey_parse_public_rsa1_fileblob(buffer, NULL, NULL)) == 0) { | ||
3835 | return sshkey_parse_private_fileblob_type(buffer, KEY_RSA1, | ||
3836 | passphrase, keyp, commentp); | ||
3837 | } | ||
3838 | #endif /* WITH_SSH1 */ | ||
3839 | if ((r = sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC, | ||
3840 | passphrase, keyp, commentp)) == 0) | ||
3841 | return 0; | ||
3842 | return r; | ||
3843 | } | ||
diff --git a/sshkey.h b/sshkey.h new file mode 100644 index 000000000..4127db244 --- /dev/null +++ b/sshkey.h | |||
@@ -0,0 +1,222 @@ | |||
1 | /* $OpenBSD: sshkey.h,v 1.1 2014/06/24 01:16:58 djm Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | */ | ||
26 | #ifndef SSHKEY_H | ||
27 | #define SSHKEY_H | ||
28 | |||
29 | #include <sys/types.h> | ||
30 | |||
31 | #ifdef WITH_OPENSSL | ||
32 | #include <openssl/rsa.h> | ||
33 | #include <openssl/dsa.h> | ||
34 | #include <openssl/ec.h> | ||
35 | #else /* OPENSSL */ | ||
36 | #define RSA void | ||
37 | #define DSA void | ||
38 | #define EC_KEY void | ||
39 | #define EC_GROUP void | ||
40 | #define EC_POINT void | ||
41 | #endif /* WITH_OPENSSL */ | ||
42 | |||
43 | #define SSH_RSA_MINIMUM_MODULUS_SIZE 768 | ||
44 | #define SSH_KEY_MAX_SIGN_DATA_SIZE (1 << 20) | ||
45 | |||
46 | struct sshbuf; | ||
47 | |||
48 | /* Key types */ | ||
49 | enum sshkey_types { | ||
50 | KEY_RSA1, | ||
51 | KEY_RSA, | ||
52 | KEY_DSA, | ||
53 | KEY_ECDSA, | ||
54 | KEY_ED25519, | ||
55 | KEY_RSA_CERT, | ||
56 | KEY_DSA_CERT, | ||
57 | KEY_ECDSA_CERT, | ||
58 | KEY_ED25519_CERT, | ||
59 | KEY_RSA_CERT_V00, | ||
60 | KEY_DSA_CERT_V00, | ||
61 | KEY_UNSPEC | ||
62 | }; | ||
63 | |||
64 | /* Fingerprint hash algorithms */ | ||
65 | enum sshkey_fp_type { | ||
66 | SSH_FP_SHA1, | ||
67 | SSH_FP_MD5, | ||
68 | SSH_FP_SHA256 | ||
69 | }; | ||
70 | |||
71 | /* Fingerprint representation formats */ | ||
72 | enum sshkey_fp_rep { | ||
73 | SSH_FP_HEX, | ||
74 | SSH_FP_BUBBLEBABBLE, | ||
75 | SSH_FP_RANDOMART | ||
76 | }; | ||
77 | |||
78 | /* key is stored in external hardware */ | ||
79 | #define SSHKEY_FLAG_EXT 0x0001 | ||
80 | |||
81 | #define SSHKEY_CERT_MAX_PRINCIPALS 256 | ||
82 | /* XXX opaquify? */ | ||
83 | struct sshkey_cert { | ||
84 | struct sshbuf *certblob; /* Kept around for use on wire */ | ||
85 | u_int type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */ | ||
86 | u_int64_t serial; | ||
87 | char *key_id; | ||
88 | u_int nprincipals; | ||
89 | char **principals; | ||
90 | u_int64_t valid_after, valid_before; | ||
91 | struct sshbuf *critical; | ||
92 | struct sshbuf *extensions; | ||
93 | struct sshkey *signature_key; | ||
94 | }; | ||
95 | |||
96 | /* XXX opaquify? */ | ||
97 | struct sshkey { | ||
98 | int type; | ||
99 | int flags; | ||
100 | RSA *rsa; | ||
101 | DSA *dsa; | ||
102 | int ecdsa_nid; /* NID of curve */ | ||
103 | EC_KEY *ecdsa; | ||
104 | u_char *ed25519_sk; | ||
105 | u_char *ed25519_pk; | ||
106 | struct sshkey_cert *cert; | ||
107 | }; | ||
108 | |||
109 | #define ED25519_SK_SZ crypto_sign_ed25519_SECRETKEYBYTES | ||
110 | #define ED25519_PK_SZ crypto_sign_ed25519_PUBLICKEYBYTES | ||
111 | |||
112 | struct sshkey *sshkey_new(int); | ||
113 | int sshkey_add_private(struct sshkey *); | ||
114 | struct sshkey *sshkey_new_private(int); | ||
115 | void sshkey_free(struct sshkey *); | ||
116 | int sshkey_demote(const struct sshkey *, struct sshkey **); | ||
117 | int sshkey_equal_public(const struct sshkey *, | ||
118 | const struct sshkey *); | ||
119 | int sshkey_equal(const struct sshkey *, const struct sshkey *); | ||
120 | char *sshkey_fingerprint(const struct sshkey *, | ||
121 | enum sshkey_fp_type, enum sshkey_fp_rep); | ||
122 | int sshkey_fingerprint_raw(const struct sshkey *k, | ||
123 | enum sshkey_fp_type dgst_type, u_char **retp, size_t *lenp); | ||
124 | const char *sshkey_type(const struct sshkey *); | ||
125 | const char *sshkey_cert_type(const struct sshkey *); | ||
126 | int sshkey_write(const struct sshkey *, FILE *); | ||
127 | int sshkey_read(struct sshkey *, char **); | ||
128 | u_int sshkey_size(const struct sshkey *); | ||
129 | |||
130 | int sshkey_generate(int type, u_int bits, struct sshkey **keyp); | ||
131 | int sshkey_from_private(const struct sshkey *, struct sshkey **); | ||
132 | int sshkey_type_from_name(const char *); | ||
133 | int sshkey_is_cert(const struct sshkey *); | ||
134 | int sshkey_type_is_cert(int); | ||
135 | int sshkey_type_plain(int); | ||
136 | int sshkey_to_certified(struct sshkey *, int); | ||
137 | int sshkey_drop_cert(struct sshkey *); | ||
138 | int sshkey_certify(struct sshkey *, struct sshkey *); | ||
139 | int sshkey_cert_copy(const struct sshkey *, struct sshkey *); | ||
140 | int sshkey_cert_check_authority(const struct sshkey *, int, int, | ||
141 | const char *, const char **); | ||
142 | int sshkey_cert_is_legacy(const struct sshkey *); | ||
143 | |||
144 | int sshkey_ecdsa_nid_from_name(const char *); | ||
145 | int sshkey_curve_name_to_nid(const char *); | ||
146 | const char * sshkey_curve_nid_to_name(int); | ||
147 | u_int sshkey_curve_nid_to_bits(int); | ||
148 | int sshkey_ecdsa_bits_to_nid(int); | ||
149 | int sshkey_ecdsa_key_to_nid(EC_KEY *); | ||
150 | int sshkey_ec_nid_to_hash_alg(int nid); | ||
151 | int sshkey_ec_validate_public(const EC_GROUP *, const EC_POINT *); | ||
152 | int sshkey_ec_validate_private(const EC_KEY *); | ||
153 | const char *sshkey_ssh_name(const struct sshkey *); | ||
154 | const char *sshkey_ssh_name_plain(const struct sshkey *); | ||
155 | int sshkey_names_valid2(const char *); | ||
156 | char *key_alg_list(int, int); | ||
157 | |||
158 | int sshkey_from_blob(const u_char *, size_t, struct sshkey **); | ||
159 | int sshkey_to_blob_buf(const struct sshkey *, struct sshbuf *); | ||
160 | int sshkey_to_blob(const struct sshkey *, u_char **, size_t *); | ||
161 | int sshkey_plain_to_blob_buf(const struct sshkey *, struct sshbuf *); | ||
162 | int sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *); | ||
163 | |||
164 | int sshkey_sign(const struct sshkey *, u_char **, size_t *, | ||
165 | const u_char *, size_t, u_int); | ||
166 | int sshkey_verify(const struct sshkey *, const u_char *, size_t, | ||
167 | const u_char *, size_t, u_int); | ||
168 | |||
169 | /* for debug */ | ||
170 | void sshkey_dump_ec_point(const EC_GROUP *, const EC_POINT *); | ||
171 | void sshkey_dump_ec_key(const EC_KEY *); | ||
172 | |||
173 | /* private key parsing and serialisation */ | ||
174 | int sshkey_private_serialize(const struct sshkey *key, struct sshbuf *buf); | ||
175 | int sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **keyp); | ||
176 | |||
177 | /* private key file format parsing and serialisation */ | ||
178 | int sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob, | ||
179 | const char *passphrase, const char *comment, | ||
180 | int force_new_format, const char *new_format_cipher, int new_format_rounds); | ||
181 | int sshkey_parse_public_rsa1_fileblob(struct sshbuf *blob, | ||
182 | struct sshkey **keyp, char **commentp); | ||
183 | int sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, | ||
184 | const char *passphrase, struct sshkey **keyp, char **commentp); | ||
185 | int sshkey_parse_private_fileblob(struct sshbuf *buffer, | ||
186 | const char *passphrase, const char *filename, struct sshkey **keyp, | ||
187 | char **commentp); | ||
188 | int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type, | ||
189 | const char *passphrase, struct sshkey **keyp, char **commentp); | ||
190 | |||
191 | #ifdef SSHKEY_INTERNAL | ||
192 | int ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, | ||
193 | const u_char *data, size_t datalen, u_int compat); | ||
194 | int ssh_rsa_verify(const struct sshkey *key, | ||
195 | const u_char *signature, size_t signaturelen, | ||
196 | const u_char *data, size_t datalen, u_int compat); | ||
197 | int ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, | ||
198 | const u_char *data, size_t datalen, u_int compat); | ||
199 | int ssh_dss_verify(const struct sshkey *key, | ||
200 | const u_char *signature, size_t signaturelen, | ||
201 | const u_char *data, size_t datalen, u_int compat); | ||
202 | int ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, | ||
203 | const u_char *data, size_t datalen, u_int compat); | ||
204 | int ssh_ecdsa_verify(const struct sshkey *key, | ||
205 | const u_char *signature, size_t signaturelen, | ||
206 | const u_char *data, size_t datalen, u_int compat); | ||
207 | int ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, | ||
208 | const u_char *data, size_t datalen, u_int compat); | ||
209 | int ssh_ed25519_verify(const struct sshkey *key, | ||
210 | const u_char *signature, size_t signaturelen, | ||
211 | const u_char *data, size_t datalen, u_int compat); | ||
212 | #endif | ||
213 | |||
214 | #ifndef WITH_OPENSSL | ||
215 | #undef RSA | ||
216 | #undef DSA | ||
217 | #undef EC_KEY | ||
218 | #undef EC_GROUP | ||
219 | #undef EC_POINT | ||
220 | #endif /* WITH_OPENSSL */ | ||
221 | |||
222 | #endif /* SSHKEY_H */ | ||