diff options
Diffstat (limited to 'ssh-ecdsa.c')
-rw-r--r-- | ssh-ecdsa.c | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c new file mode 100644 index 000000000..c8276b460 --- /dev/null +++ b/ssh-ecdsa.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* $OpenBSD: ssh-ecdsa.c,v 1.4 2010/09/10 01:04:10 djm Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | ||
4 | * Copyright (c) 2010 Damien Miller. 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 | |||
27 | #include "includes.h" | ||
28 | |||
29 | #ifdef OPENSSL_HAS_ECC | ||
30 | |||
31 | #include <sys/types.h> | ||
32 | |||
33 | #include <openssl/bn.h> | ||
34 | #include <openssl/ec.h> | ||
35 | #include <openssl/ecdsa.h> | ||
36 | #include <openssl/evp.h> | ||
37 | |||
38 | #include <string.h> | ||
39 | |||
40 | #include "xmalloc.h" | ||
41 | #include "buffer.h" | ||
42 | #include "compat.h" | ||
43 | #include "log.h" | ||
44 | #include "key.h" | ||
45 | |||
46 | int | ||
47 | ssh_ecdsa_sign(const Key *key, u_char **sigp, u_int *lenp, | ||
48 | const u_char *data, u_int datalen) | ||
49 | { | ||
50 | ECDSA_SIG *sig; | ||
51 | const EVP_MD *evp_md; | ||
52 | EVP_MD_CTX md; | ||
53 | u_char digest[EVP_MAX_MD_SIZE]; | ||
54 | u_int len, dlen; | ||
55 | Buffer b, bb; | ||
56 | |||
57 | if (key == NULL || key->ecdsa == NULL || | ||
58 | (key->type != KEY_ECDSA && key->type != KEY_ECDSA_CERT)) { | ||
59 | error("%s: no ECDSA key", __func__); | ||
60 | return -1; | ||
61 | } | ||
62 | evp_md = key_ec_nid_to_evpmd(key->ecdsa_nid); | ||
63 | EVP_DigestInit(&md, evp_md); | ||
64 | EVP_DigestUpdate(&md, data, datalen); | ||
65 | EVP_DigestFinal(&md, digest, &dlen); | ||
66 | |||
67 | sig = ECDSA_do_sign(digest, dlen, key->ecdsa); | ||
68 | memset(digest, 'd', sizeof(digest)); | ||
69 | |||
70 | if (sig == NULL) { | ||
71 | error("%s: sign failed", __func__); | ||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | buffer_init(&bb); | ||
76 | buffer_put_bignum2(&bb, sig->r); | ||
77 | buffer_put_bignum2(&bb, sig->s); | ||
78 | ECDSA_SIG_free(sig); | ||
79 | |||
80 | buffer_init(&b); | ||
81 | buffer_put_cstring(&b, key_ssh_name_plain(key)); | ||
82 | buffer_put_string(&b, buffer_ptr(&bb), buffer_len(&bb)); | ||
83 | buffer_free(&bb); | ||
84 | len = buffer_len(&b); | ||
85 | if (lenp != NULL) | ||
86 | *lenp = len; | ||
87 | if (sigp != NULL) { | ||
88 | *sigp = xmalloc(len); | ||
89 | memcpy(*sigp, buffer_ptr(&b), len); | ||
90 | } | ||
91 | buffer_free(&b); | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | int | ||
96 | ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen, | ||
97 | const u_char *data, u_int datalen) | ||
98 | { | ||
99 | ECDSA_SIG *sig; | ||
100 | const EVP_MD *evp_md; | ||
101 | EVP_MD_CTX md; | ||
102 | u_char digest[EVP_MAX_MD_SIZE], *sigblob; | ||
103 | u_int len, dlen; | ||
104 | int rlen, ret; | ||
105 | Buffer b, bb; | ||
106 | char *ktype; | ||
107 | |||
108 | if (key == NULL || key->ecdsa == NULL || | ||
109 | (key->type != KEY_ECDSA && key->type != KEY_ECDSA_CERT)) { | ||
110 | error("%s: no ECDSA key", __func__); | ||
111 | return -1; | ||
112 | } | ||
113 | evp_md = key_ec_nid_to_evpmd(key->ecdsa_nid); | ||
114 | |||
115 | /* fetch signature */ | ||
116 | buffer_init(&b); | ||
117 | buffer_append(&b, signature, signaturelen); | ||
118 | ktype = buffer_get_string(&b, NULL); | ||
119 | if (strcmp(key_ssh_name_plain(key), ktype) != 0) { | ||
120 | error("%s: cannot handle type %s", __func__, ktype); | ||
121 | buffer_free(&b); | ||
122 | xfree(ktype); | ||
123 | return -1; | ||
124 | } | ||
125 | xfree(ktype); | ||
126 | sigblob = buffer_get_string(&b, &len); | ||
127 | rlen = buffer_len(&b); | ||
128 | buffer_free(&b); | ||
129 | if (rlen != 0) { | ||
130 | error("%s: remaining bytes in signature %d", __func__, rlen); | ||
131 | xfree(sigblob); | ||
132 | return -1; | ||
133 | } | ||
134 | |||
135 | /* parse signature */ | ||
136 | if ((sig = ECDSA_SIG_new()) == NULL) | ||
137 | fatal("%s: ECDSA_SIG_new failed", __func__); | ||
138 | if ((sig->r = BN_new()) == NULL || | ||
139 | (sig->s = BN_new()) == NULL) | ||
140 | fatal("%s: BN_new failed", __func__); | ||
141 | |||
142 | buffer_init(&bb); | ||
143 | buffer_append(&bb, sigblob, len); | ||
144 | buffer_get_bignum2(&bb, sig->r); | ||
145 | buffer_get_bignum2(&bb, sig->s); | ||
146 | if (buffer_len(&bb) != 0) | ||
147 | fatal("%s: remaining bytes in inner sigblob", __func__); | ||
148 | |||
149 | /* clean up */ | ||
150 | memset(sigblob, 0, len); | ||
151 | xfree(sigblob); | ||
152 | |||
153 | /* hash the data */ | ||
154 | EVP_DigestInit(&md, evp_md); | ||
155 | EVP_DigestUpdate(&md, data, datalen); | ||
156 | EVP_DigestFinal(&md, digest, &dlen); | ||
157 | |||
158 | ret = ECDSA_do_verify(digest, dlen, sig, key->ecdsa); | ||
159 | memset(digest, 'd', sizeof(digest)); | ||
160 | |||
161 | ECDSA_SIG_free(sig); | ||
162 | |||
163 | debug("%s: signature %s", __func__, | ||
164 | ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | #endif /* OPENSSL_HAS_ECC */ | ||