diff options
Diffstat (limited to 'sshkey.c')
-rw-r--r-- | sshkey.c | 93 |
1 files changed, 67 insertions, 26 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshkey.c,v 1.66 2018/07/03 13:20:25 djm Exp $ */ | 1 | /* $OpenBSD: sshkey.c,v 1.67 2018/09/12 01:31:30 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Alexander von Gernler. All rights reserved. | 4 | * Copyright (c) 2008 Alexander von Gernler. All rights reserved. |
@@ -78,6 +78,7 @@ int sshkey_private_serialize_opt(const struct sshkey *key, | |||
78 | struct sshbuf *buf, enum sshkey_serialize_rep); | 78 | struct sshbuf *buf, enum sshkey_serialize_rep); |
79 | static int sshkey_from_blob_internal(struct sshbuf *buf, | 79 | static int sshkey_from_blob_internal(struct sshbuf *buf, |
80 | struct sshkey **keyp, int allow_cert); | 80 | struct sshkey **keyp, int allow_cert); |
81 | static int get_sigtype(const u_char *sig, size_t siglen, char **sigtypep); | ||
81 | 82 | ||
82 | /* Supported key types */ | 83 | /* Supported key types */ |
83 | struct keytype { | 84 | struct keytype { |
@@ -453,6 +454,7 @@ cert_free(struct sshkey_cert *cert) | |||
453 | free(cert->principals[i]); | 454 | free(cert->principals[i]); |
454 | free(cert->principals); | 455 | free(cert->principals); |
455 | sshkey_free(cert->signature_key); | 456 | sshkey_free(cert->signature_key); |
457 | free(cert->signature_type); | ||
456 | freezero(cert, sizeof(*cert)); | 458 | freezero(cert, sizeof(*cert)); |
457 | } | 459 | } |
458 | 460 | ||
@@ -472,6 +474,7 @@ cert_new(void) | |||
472 | cert->key_id = NULL; | 474 | cert->key_id = NULL; |
473 | cert->principals = NULL; | 475 | cert->principals = NULL; |
474 | cert->signature_key = NULL; | 476 | cert->signature_key = NULL; |
477 | cert->signature_type = NULL; | ||
475 | return cert; | 478 | return cert; |
476 | } | 479 | } |
477 | 480 | ||
@@ -1695,54 +1698,68 @@ sshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key) | |||
1695 | u_int i; | 1698 | u_int i; |
1696 | const struct sshkey_cert *from; | 1699 | const struct sshkey_cert *from; |
1697 | struct sshkey_cert *to; | 1700 | struct sshkey_cert *to; |
1698 | int ret = SSH_ERR_INTERNAL_ERROR; | 1701 | int r = SSH_ERR_INTERNAL_ERROR; |
1699 | |||
1700 | if (to_key->cert != NULL) { | ||
1701 | cert_free(to_key->cert); | ||
1702 | to_key->cert = NULL; | ||
1703 | } | ||
1704 | 1702 | ||
1705 | if ((from = from_key->cert) == NULL) | 1703 | if (to_key == NULL || (from = from_key->cert) == NULL) |
1706 | return SSH_ERR_INVALID_ARGUMENT; | 1704 | return SSH_ERR_INVALID_ARGUMENT; |
1707 | 1705 | ||
1708 | if ((to = to_key->cert = cert_new()) == NULL) | 1706 | if ((to = cert_new()) == NULL) |
1709 | return SSH_ERR_ALLOC_FAIL; | 1707 | return SSH_ERR_ALLOC_FAIL; |
1710 | 1708 | ||
1711 | if ((ret = sshbuf_putb(to->certblob, from->certblob)) != 0 || | 1709 | if ((r = sshbuf_putb(to->certblob, from->certblob)) != 0 || |
1712 | (ret = sshbuf_putb(to->critical, from->critical)) != 0 || | 1710 | (r = sshbuf_putb(to->critical, from->critical)) != 0 || |
1713 | (ret = sshbuf_putb(to->extensions, from->extensions)) != 0) | 1711 | (r = sshbuf_putb(to->extensions, from->extensions)) != 0) |
1714 | return ret; | 1712 | goto out; |
1715 | 1713 | ||
1716 | to->serial = from->serial; | 1714 | to->serial = from->serial; |
1717 | to->type = from->type; | 1715 | to->type = from->type; |
1718 | if (from->key_id == NULL) | 1716 | if (from->key_id == NULL) |
1719 | to->key_id = NULL; | 1717 | to->key_id = NULL; |
1720 | else if ((to->key_id = strdup(from->key_id)) == NULL) | 1718 | else if ((to->key_id = strdup(from->key_id)) == NULL) { |
1721 | return SSH_ERR_ALLOC_FAIL; | 1719 | r = SSH_ERR_ALLOC_FAIL; |
1720 | goto out; | ||
1721 | } | ||
1722 | to->valid_after = from->valid_after; | 1722 | to->valid_after = from->valid_after; |
1723 | to->valid_before = from->valid_before; | 1723 | to->valid_before = from->valid_before; |
1724 | if (from->signature_key == NULL) | 1724 | if (from->signature_key == NULL) |
1725 | to->signature_key = NULL; | 1725 | to->signature_key = NULL; |
1726 | else if ((ret = sshkey_from_private(from->signature_key, | 1726 | else if ((r = sshkey_from_private(from->signature_key, |
1727 | &to->signature_key)) != 0) | 1727 | &to->signature_key)) != 0) |
1728 | return ret; | 1728 | goto out; |
1729 | 1729 | if (from->signature_type != NULL && | |
1730 | if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS) | 1730 | (to->signature_type = strdup(from->signature_type)) == NULL) { |
1731 | return SSH_ERR_INVALID_ARGUMENT; | 1731 | r = SSH_ERR_ALLOC_FAIL; |
1732 | goto out; | ||
1733 | } | ||
1734 | if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS) { | ||
1735 | r = SSH_ERR_INVALID_ARGUMENT; | ||
1736 | goto out; | ||
1737 | } | ||
1732 | if (from->nprincipals > 0) { | 1738 | if (from->nprincipals > 0) { |
1733 | if ((to->principals = calloc(from->nprincipals, | 1739 | if ((to->principals = calloc(from->nprincipals, |
1734 | sizeof(*to->principals))) == NULL) | 1740 | sizeof(*to->principals))) == NULL) { |
1735 | return SSH_ERR_ALLOC_FAIL; | 1741 | r = SSH_ERR_ALLOC_FAIL; |
1742 | goto out; | ||
1743 | } | ||
1736 | for (i = 0; i < from->nprincipals; i++) { | 1744 | for (i = 0; i < from->nprincipals; i++) { |
1737 | to->principals[i] = strdup(from->principals[i]); | 1745 | to->principals[i] = strdup(from->principals[i]); |
1738 | if (to->principals[i] == NULL) { | 1746 | if (to->principals[i] == NULL) { |
1739 | to->nprincipals = i; | 1747 | to->nprincipals = i; |
1740 | return SSH_ERR_ALLOC_FAIL; | 1748 | r = SSH_ERR_ALLOC_FAIL; |
1749 | goto out; | ||
1741 | } | 1750 | } |
1742 | } | 1751 | } |
1743 | } | 1752 | } |
1744 | to->nprincipals = from->nprincipals; | 1753 | to->nprincipals = from->nprincipals; |
1745 | return 0; | 1754 | |
1755 | /* success */ | ||
1756 | cert_free(to_key->cert); | ||
1757 | to_key->cert = to; | ||
1758 | to = NULL; | ||
1759 | r = 0; | ||
1760 | out: | ||
1761 | cert_free(to); | ||
1762 | return r; | ||
1746 | } | 1763 | } |
1747 | 1764 | ||
1748 | int | 1765 | int |
@@ -1954,6 +1971,8 @@ cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf) | |||
1954 | if ((ret = sshkey_verify(key->cert->signature_key, sig, slen, | 1971 | if ((ret = sshkey_verify(key->cert->signature_key, sig, slen, |
1955 | sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0)) != 0) | 1972 | sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0)) != 0) |
1956 | goto out; | 1973 | goto out; |
1974 | if ((ret = get_sigtype(sig, slen, &key->cert->signature_type)) != 0) | ||
1975 | goto out; | ||
1957 | 1976 | ||
1958 | /* Success */ | 1977 | /* Success */ |
1959 | ret = 0; | 1978 | ret = 0; |
@@ -2531,7 +2550,8 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg, | |||
2531 | u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32]; | 2550 | u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32]; |
2532 | size_t i, ca_len, sig_len; | 2551 | size_t i, ca_len, sig_len; |
2533 | int ret = SSH_ERR_INTERNAL_ERROR; | 2552 | int ret = SSH_ERR_INTERNAL_ERROR; |
2534 | struct sshbuf *cert; | 2553 | struct sshbuf *cert = NULL; |
2554 | char *sigtype = NULL; | ||
2535 | 2555 | ||
2536 | if (k == NULL || k->cert == NULL || | 2556 | if (k == NULL || k->cert == NULL || |
2537 | k->cert->certblob == NULL || ca == NULL) | 2557 | k->cert->certblob == NULL || ca == NULL) |
@@ -2541,6 +2561,16 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg, | |||
2541 | if (!sshkey_type_is_valid_ca(ca->type)) | 2561 | if (!sshkey_type_is_valid_ca(ca->type)) |
2542 | return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; | 2562 | return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; |
2543 | 2563 | ||
2564 | /* | ||
2565 | * If no alg specified as argument but a signature_type was set, | ||
2566 | * then prefer that. If both were specified, then they must match. | ||
2567 | */ | ||
2568 | if (alg == NULL) | ||
2569 | alg = k->cert->signature_type; | ||
2570 | else if (k->cert->signature_type != NULL && | ||
2571 | strcmp(alg, k->cert->signature_type) != 0) | ||
2572 | return SSH_ERR_INVALID_ARGUMENT; | ||
2573 | |||
2544 | if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0) | 2574 | if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0) |
2545 | return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; | 2575 | return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; |
2546 | 2576 | ||
@@ -2629,7 +2659,17 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg, | |||
2629 | if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert), | 2659 | if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert), |
2630 | sshbuf_len(cert), alg, 0, signer_ctx)) != 0) | 2660 | sshbuf_len(cert), alg, 0, signer_ctx)) != 0) |
2631 | goto out; | 2661 | goto out; |
2632 | 2662 | /* Check and update signature_type against what was actually used */ | |
2663 | if ((ret = get_sigtype(sig_blob, sig_len, &sigtype)) != 0) | ||
2664 | goto out; | ||
2665 | if (alg != NULL && strcmp(alg, sigtype) != 0) { | ||
2666 | ret = SSH_ERR_SIGN_ALG_UNSUPPORTED; | ||
2667 | goto out; | ||
2668 | } | ||
2669 | if (k->cert->signature_type == NULL) { | ||
2670 | k->cert->signature_type = sigtype; | ||
2671 | sigtype = NULL; | ||
2672 | } | ||
2633 | /* Append signature and we are done */ | 2673 | /* Append signature and we are done */ |
2634 | if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0) | 2674 | if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0) |
2635 | goto out; | 2675 | goto out; |
@@ -2639,6 +2679,7 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg, | |||
2639 | sshbuf_reset(cert); | 2679 | sshbuf_reset(cert); |
2640 | free(sig_blob); | 2680 | free(sig_blob); |
2641 | free(ca_blob); | 2681 | free(ca_blob); |
2682 | free(sigtype); | ||
2642 | sshbuf_free(principals); | 2683 | sshbuf_free(principals); |
2643 | return ret; | 2684 | return ret; |
2644 | } | 2685 | } |