1 /* $OpenBSD: ssh-dss.c,v 1.48 2022/10/28 00:44:44 djm Exp $ */ 2 /* 3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include <sys/types.h> 27 28 #include <openssl/bn.h> 29 #include <openssl/evp.h> 30 31 #include <string.h> 32 33 #include "sshbuf.h" 34 #include "compat.h" 35 #include "ssherr.h" 36 #include "digest.h" 37 #define SSHKEY_INTERNAL 38 #include "sshkey.h" 39 40 #define INTBLOB_LEN 20 41 #define SIGBLOB_LEN (2*INTBLOB_LEN) 42 43 static u_int 44 ssh_dss_size(const struct sshkey *key) 45 { 46 const BIGNUM *dsa_p; 47 48 if (key->dsa == NULL) 49 return 0; 50 DSA_get0_pqg(key->dsa, &dsa_p, NULL, NULL); 51 return BN_num_bits(dsa_p); 52 } 53 54 static int 55 ssh_dss_alloc(struct sshkey *k) 56 { 57 if ((k->dsa = DSA_new()) == NULL) 58 return SSH_ERR_ALLOC_FAIL; 59 return 0; 60 } 61 62 static void 63 ssh_dss_cleanup(struct sshkey *k) 64 { 65 DSA_free(k->dsa); 66 k->dsa = NULL; 67 } 68 69 static int 70 ssh_dss_equal(const struct sshkey *a, const struct sshkey *b) 71 { 72 const BIGNUM *dsa_p_a, *dsa_q_a, *dsa_g_a, *dsa_pub_key_a; 73 const BIGNUM *dsa_p_b, *dsa_q_b, *dsa_g_b, *dsa_pub_key_b; 74 75 if (a->dsa == NULL || b->dsa == NULL) 76 return 0; 77 DSA_get0_pqg(a->dsa, &dsa_p_a, &dsa_q_a, &dsa_g_a); 78 DSA_get0_pqg(b->dsa, &dsa_p_b, &dsa_q_b, &dsa_g_b); 79 DSA_get0_key(a->dsa, &dsa_pub_key_a, NULL); 80 DSA_get0_key(b->dsa, &dsa_pub_key_b, NULL); 81 if (dsa_p_a == NULL || dsa_p_b == NULL || 82 dsa_q_a == NULL || dsa_q_b == NULL || 83 dsa_g_a == NULL || dsa_g_b == NULL || 84 dsa_pub_key_a == NULL || dsa_pub_key_b == NULL) 85 return 0; 86 if (BN_cmp(dsa_p_a, dsa_p_b) != 0) 87 return 0; 88 if (BN_cmp(dsa_q_a, dsa_q_b) != 0) 89 return 0; 90 if (BN_cmp(dsa_g_a, dsa_g_b) != 0) 91 return 0; 92 if (BN_cmp(dsa_pub_key_a, dsa_pub_key_b) != 0) 93 return 0; 94 return 1; 95 } 96 97 static int 98 ssh_dss_serialize_public(const struct sshkey *key, struct sshbuf *b, 99 enum sshkey_serialize_rep opts) 100 { 101 int r; 102 const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key; 103 104 if (key->dsa == NULL) 105 return SSH_ERR_INVALID_ARGUMENT; 106 DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g); 107 DSA_get0_key(key->dsa, &dsa_pub_key, NULL); 108 if (dsa_p == NULL || dsa_q == NULL || 109 dsa_g == NULL || dsa_pub_key == NULL) 110 return SSH_ERR_INTERNAL_ERROR; 111 if ((r = sshbuf_put_bignum2(b, dsa_p)) != 0 || 112 (r = sshbuf_put_bignum2(b, dsa_q)) != 0 || 113 (r = sshbuf_put_bignum2(b, dsa_g)) != 0 || 114 (r = sshbuf_put_bignum2(b, dsa_pub_key)) != 0) 115 return r; 116 117 return 0; 118 } 119 120 static int 121 ssh_dss_serialize_private(const struct sshkey *key, struct sshbuf *b, 122 enum sshkey_serialize_rep opts) 123 { 124 int r; 125 const BIGNUM *dsa_priv_key; 126 127 DSA_get0_key(key->dsa, NULL, &dsa_priv_key); 128 if (!sshkey_is_cert(key)) { 129 if ((r = ssh_dss_serialize_public(key, b, opts)) != 0) 130 return r; 131 } 132 if ((r = sshbuf_put_bignum2(b, dsa_priv_key)) != 0) 133 return r; 134 135 return 0; 136 } 137 138 static int 139 ssh_dss_generate(struct sshkey *k, int bits) 140 { 141 DSA *private; 142 143 if (bits != 1024) 144 return SSH_ERR_KEY_LENGTH; 145 if ((private = DSA_new()) == NULL) 146 return SSH_ERR_ALLOC_FAIL; 147 if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL, 148 NULL, NULL) || !DSA_generate_key(private)) { 149 DSA_free(private); 150 return SSH_ERR_LIBCRYPTO_ERROR; 151 } 152 k->dsa = private; 153 return 0; 154 } 155 156 static int 157 ssh_dss_copy_public(const struct sshkey *from, struct sshkey *to) 158 { 159 const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key; 160 BIGNUM *dsa_p_dup = NULL, *dsa_q_dup = NULL, *dsa_g_dup = NULL; 161 BIGNUM *dsa_pub_key_dup = NULL; 162 int r = SSH_ERR_INTERNAL_ERROR; 163 164 DSA_get0_pqg(from->dsa, &dsa_p, &dsa_q, &dsa_g); 165 DSA_get0_key(from->dsa, &dsa_pub_key, NULL); 166 if ((dsa_p_dup = BN_dup(dsa_p)) == NULL || 167 (dsa_q_dup = BN_dup(dsa_q)) == NULL || 168 (dsa_g_dup = BN_dup(dsa_g)) == NULL || 169 (dsa_pub_key_dup = BN_dup(dsa_pub_key)) == NULL) { 170 r = SSH_ERR_ALLOC_FAIL; 171 goto out; 172 } 173 if (!DSA_set0_pqg(to->dsa, dsa_p_dup, dsa_q_dup, dsa_g_dup)) { 174 r = SSH_ERR_LIBCRYPTO_ERROR; 175 goto out; 176 } 177 dsa_p_dup = dsa_q_dup = dsa_g_dup = NULL; /* transferred */ 178 if (!DSA_set0_key(to->dsa, dsa_pub_key_dup, NULL)) { 179 r = SSH_ERR_LIBCRYPTO_ERROR; 180 goto out; 181 } 182 dsa_pub_key_dup = NULL; /* transferred */ 183 /* success */ 184 r = 0; 185 out: 186 BN_clear_free(dsa_p_dup); 187 BN_clear_free(dsa_q_dup); 188 BN_clear_free(dsa_g_dup); 189 BN_clear_free(dsa_pub_key_dup); 190 return r; 191 } 192 193 static int 194 ssh_dss_deserialize_public(const char *ktype, struct sshbuf *b, 195 struct sshkey *key) 196 { 197 int ret = SSH_ERR_INTERNAL_ERROR; 198 BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL; 199 200 if (sshbuf_get_bignum2(b, &dsa_p) != 0 || 201 sshbuf_get_bignum2(b, &dsa_q) != 0 || 202 sshbuf_get_bignum2(b, &dsa_g) != 0 || 203 sshbuf_get_bignum2(b, &dsa_pub_key) != 0) { 204 ret = SSH_ERR_INVALID_FORMAT; 205 goto out; 206 } 207 if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) { 208 ret = SSH_ERR_LIBCRYPTO_ERROR; 209 goto out; 210 } 211 dsa_p = dsa_q = dsa_g = NULL; /* transferred */ 212 if (!DSA_set0_key(key->dsa, dsa_pub_key, NULL)) { 213 ret = SSH_ERR_LIBCRYPTO_ERROR; 214 goto out; 215 } 216 dsa_pub_key = NULL; /* transferred */ 217 #ifdef DEBUG_PK 218 DSA_print_fp(stderr, key->dsa, 8); 219 #endif 220 /* success */ 221 ret = 0; 222 out: 223 BN_clear_free(dsa_p); 224 BN_clear_free(dsa_q); 225 BN_clear_free(dsa_g); 226 BN_clear_free(dsa_pub_key); 227 return ret; 228 } 229 230 static int 231 ssh_dss_deserialize_private(const char *ktype, struct sshbuf *b, 232 struct sshkey *key) 233 { 234 int r; 235 BIGNUM *dsa_priv_key = NULL; 236 237 if (!sshkey_is_cert(key)) { 238 if ((r = ssh_dss_deserialize_public(ktype, b, key)) != 0) 239 return r; 240 } 241 242 if ((r = sshbuf_get_bignum2(b, &dsa_priv_key)) != 0) 243 return r; 244 if (!DSA_set0_key(key->dsa, NULL, dsa_priv_key)) { 245 BN_clear_free(dsa_priv_key); 246 return SSH_ERR_LIBCRYPTO_ERROR; 247 } 248 return 0; 249 } 250 251 static int 252 ssh_dss_sign(struct sshkey *key, 253 u_char **sigp, size_t *lenp, 254 const u_char *data, size_t datalen, 255 const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) 256 { 257 DSA_SIG *sig = NULL; 258 const BIGNUM *sig_r, *sig_s; 259 u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; 260 size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 261 struct sshbuf *b = NULL; 262 int ret = SSH_ERR_INVALID_ARGUMENT; 263 264 if (lenp != NULL) 265 *lenp = 0; 266 if (sigp != NULL) 267 *sigp = NULL; 268 269 if (key == NULL || key->dsa == NULL || 270 sshkey_type_plain(key->type) != KEY_DSA) 271 return SSH_ERR_INVALID_ARGUMENT; 272 if (dlen == 0) 273 return SSH_ERR_INTERNAL_ERROR; 274 275 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 276 digest, sizeof(digest))) != 0) 277 goto out; 278 279 if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { 280 ret = SSH_ERR_LIBCRYPTO_ERROR; 281 goto out; 282 } 283 284 DSA_SIG_get0(sig, &sig_r, &sig_s); 285 rlen = BN_num_bytes(sig_r); 286 slen = BN_num_bytes(sig_s); 287 if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 288 ret = SSH_ERR_INTERNAL_ERROR; 289 goto out; 290 } 291 explicit_bzero(sigblob, SIGBLOB_LEN); 292 BN_bn2bin(sig_r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); 293 BN_bn2bin(sig_s, sigblob + SIGBLOB_LEN - slen); 294 295 if ((b = sshbuf_new()) == NULL) { 296 ret = SSH_ERR_ALLOC_FAIL; 297 goto out; 298 } 299 if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 || 300 (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0) 301 goto out; 302 303 len = sshbuf_len(b); 304 if (sigp != NULL) { 305 if ((*sigp = malloc(len)) == NULL) { 306 ret = SSH_ERR_ALLOC_FAIL; 307 goto out; 308 } 309 memcpy(*sigp, sshbuf_ptr(b), len); 310 } 311 if (lenp != NULL) 312 *lenp = len; 313 ret = 0; 314 out: 315 explicit_bzero(digest, sizeof(digest)); 316 DSA_SIG_free(sig); 317 sshbuf_free(b); 318 return ret; 319 } 320 321 static int 322 ssh_dss_verify(const struct sshkey *key, 323 const u_char *sig, size_t siglen, 324 const u_char *data, size_t dlen, const char *alg, u_int compat, 325 struct sshkey_sig_details **detailsp) 326 { 327 DSA_SIG *dsig = NULL; 328 BIGNUM *sig_r = NULL, *sig_s = NULL; 329 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; 330 size_t len, hlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 331 int ret = SSH_ERR_INTERNAL_ERROR; 332 struct sshbuf *b = NULL; 333 char *ktype = NULL; 334 335 if (key == NULL || key->dsa == NULL || 336 sshkey_type_plain(key->type) != KEY_DSA || 337 sig == NULL || siglen == 0) 338 return SSH_ERR_INVALID_ARGUMENT; 339 if (hlen == 0) 340 return SSH_ERR_INTERNAL_ERROR; 341 342 /* fetch signature */ 343 if ((b = sshbuf_from(sig, siglen)) == NULL) 344 return SSH_ERR_ALLOC_FAIL; 345 if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || 346 sshbuf_get_string(b, &sigblob, &len) != 0) { 347 ret = SSH_ERR_INVALID_FORMAT; 348 goto out; 349 } 350 if (strcmp("ssh-dss", ktype) != 0) { 351 ret = SSH_ERR_KEY_TYPE_MISMATCH; 352 goto out; 353 } 354 if (sshbuf_len(b) != 0) { 355 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 356 goto out; 357 } 358 359 if (len != SIGBLOB_LEN) { 360 ret = SSH_ERR_INVALID_FORMAT; 361 goto out; 362 } 363 364 /* parse signature */ 365 if ((dsig = DSA_SIG_new()) == NULL || 366 (sig_r = BN_new()) == NULL || 367 (sig_s = BN_new()) == NULL) { 368 ret = SSH_ERR_ALLOC_FAIL; 369 goto out; 370 } 371 if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig_r) == NULL) || 372 (BN_bin2bn(sigblob + INTBLOB_LEN, INTBLOB_LEN, sig_s) == NULL)) { 373 ret = SSH_ERR_LIBCRYPTO_ERROR; 374 goto out; 375 } 376 if (!DSA_SIG_set0(dsig, sig_r, sig_s)) { 377 ret = SSH_ERR_LIBCRYPTO_ERROR; 378 goto out; 379 } 380 sig_r = sig_s = NULL; /* transferred */ 381 382 /* sha1 the data */ 383 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, dlen, 384 digest, sizeof(digest))) != 0) 385 goto out; 386 387 switch (DSA_do_verify(digest, hlen, dsig, key->dsa)) { 388 case 1: 389 ret = 0; 390 break; 391 case 0: 392 ret = SSH_ERR_SIGNATURE_INVALID; 393 goto out; 394 default: 395 ret = SSH_ERR_LIBCRYPTO_ERROR; 396 goto out; 397 } 398 399 out: 400 explicit_bzero(digest, sizeof(digest)); 401 DSA_SIG_free(dsig); 402 BN_clear_free(sig_r); 403 BN_clear_free(sig_s); 404 sshbuf_free(b); 405 free(ktype); 406 if (sigblob != NULL) 407 freezero(sigblob, len); 408 return ret; 409 } 410 411 static const struct sshkey_impl_funcs sshkey_dss_funcs = { 412 /* .size = */ ssh_dss_size, 413 /* .alloc = */ ssh_dss_alloc, 414 /* .cleanup = */ ssh_dss_cleanup, 415 /* .equal = */ ssh_dss_equal, 416 /* .ssh_serialize_public = */ ssh_dss_serialize_public, 417 /* .ssh_deserialize_public = */ ssh_dss_deserialize_public, 418 /* .ssh_serialize_private = */ ssh_dss_serialize_private, 419 /* .ssh_deserialize_private = */ ssh_dss_deserialize_private, 420 /* .generate = */ ssh_dss_generate, 421 /* .copy_public = */ ssh_dss_copy_public, 422 /* .sign = */ ssh_dss_sign, 423 /* .verify = */ ssh_dss_verify, 424 }; 425 426 const struct sshkey_impl sshkey_dss_impl = { 427 /* .name = */ "ssh-dss", 428 /* .shortname = */ "DSA", 429 /* .sigalg = */ NULL, 430 /* .type = */ KEY_DSA, 431 /* .nid = */ 0, 432 /* .cert = */ 0, 433 /* .sigonly = */ 0, 434 /* .keybits = */ 0, 435 /* .funcs = */ &sshkey_dss_funcs, 436 }; 437 438 const struct sshkey_impl sshkey_dsa_cert_impl = { 439 /* .name = */ "ssh-dss-cert-v01@openssh.com", 440 /* .shortname = */ "DSA-CERT", 441 /* .sigalg = */ NULL, 442 /* .type = */ KEY_DSA_CERT, 443 /* .nid = */ 0, 444 /* .cert = */ 1, 445 /* .sigonly = */ 0, 446 /* .keybits = */ 0, 447 /* .funcs = */ &sshkey_dss_funcs, 448 }; 449