[BACK]Return to ssh-dss.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/ssh-dss.c, Revision 1.33

1.33    ! mmcc        1: /* $OpenBSD: ssh-dss.c,v 1.32 2014/06/24 01:13:21 djm Exp $ */
1.1       markus      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:
1.23      deraadt    26: #include <sys/types.h>
1.4       markus     27:
                     28: #include <openssl/bn.h>
                     29: #include <openssl/evp.h>
1.22      stevesk    30:
                     31: #include <string.h>
1.1       markus     32:
1.32      djm        33: #include "sshbuf.h"
1.1       markus     34: #include "compat.h"
1.32      djm        35: #include "ssherr.h"
1.30      djm        36: #include "digest.h"
1.32      djm        37: #define SSHKEY_INTERNAL
                     38: #include "sshkey.h"
1.1       markus     39:
                     40: #define INTBLOB_LEN    20
                     41: #define SIGBLOB_LEN    (2*INTBLOB_LEN)
                     42:
                     43: int
1.32      djm        44: ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
                     45:     const u_char *data, size_t datalen, u_int compat)
1.1       markus     46: {
1.32      djm        47:        DSA_SIG *sig = NULL;
1.30      djm        48:        u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN];
1.32      djm        49:        size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
                     50:        struct sshbuf *b = NULL;
                     51:        int ret = SSH_ERR_INVALID_ARGUMENT;
                     52:
                     53:        if (lenp != NULL)
                     54:                *lenp = 0;
                     55:        if (sigp != NULL)
                     56:                *sigp = NULL;
                     57:
                     58:        if (key == NULL || key->dsa == NULL ||
                     59:            sshkey_type_plain(key->type) != KEY_DSA)
                     60:                return SSH_ERR_INVALID_ARGUMENT;
                     61:        if (dlen == 0)
                     62:                return SSH_ERR_INTERNAL_ERROR;
                     63:
                     64:        if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
                     65:            digest, sizeof(digest))) != 0)
                     66:                goto out;
                     67:
                     68:        if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) {
                     69:                ret = SSH_ERR_LIBCRYPTO_ERROR;
                     70:                goto out;
1.1       markus     71:        }
                     72:
                     73:        rlen = BN_num_bytes(sig->r);
                     74:        slen = BN_num_bytes(sig->s);
                     75:        if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
1.32      djm        76:                ret = SSH_ERR_INTERNAL_ERROR;
                     77:                goto out;
1.1       markus     78:        }
1.31      djm        79:        explicit_bzero(sigblob, SIGBLOB_LEN);
1.32      djm        80:        BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
                     81:        BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen);
1.1       markus     82:
1.32      djm        83:        if (compat & SSH_BUG_SIGBLOB) {
1.17      markus     84:                if (sigp != NULL) {
1.32      djm        85:                        if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) {
                     86:                                ret = SSH_ERR_ALLOC_FAIL;
                     87:                                goto out;
                     88:                        }
1.17      markus     89:                        memcpy(*sigp, sigblob, SIGBLOB_LEN);
                     90:                }
1.32      djm        91:                if (lenp != NULL)
                     92:                        *lenp = SIGBLOB_LEN;
                     93:                ret = 0;
1.1       markus     94:        } else {
                     95:                /* ietf-drafts */
1.32      djm        96:                if ((b = sshbuf_new()) == NULL) {
                     97:                        ret = SSH_ERR_ALLOC_FAIL;
                     98:                        goto out;
                     99:                }
                    100:                if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 ||
                    101:                    (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0)
                    102:                        goto out;
                    103:                len = sshbuf_len(b);
                    104:                if (sigp != NULL) {
                    105:                        if ((*sigp = malloc(len)) == NULL) {
                    106:                                ret = SSH_ERR_ALLOC_FAIL;
                    107:                                goto out;
                    108:                        }
                    109:                        memcpy(*sigp, sshbuf_ptr(b), len);
                    110:                }
1.1       markus    111:                if (lenp != NULL)
                    112:                        *lenp = len;
1.32      djm       113:                ret = 0;
1.1       markus    114:        }
1.32      djm       115:  out:
                    116:        explicit_bzero(digest, sizeof(digest));
                    117:        if (sig != NULL)
                    118:                DSA_SIG_free(sig);
                    119:        if (b != NULL)
                    120:                sshbuf_free(b);
                    121:        return ret;
1.1       markus    122: }
1.32      djm       123:
1.1       markus    124: int
1.32      djm       125: ssh_dss_verify(const struct sshkey *key,
                    126:     const u_char *signature, size_t signaturelen,
                    127:     const u_char *data, size_t datalen, u_int compat)
1.1       markus    128: {
1.32      djm       129:        DSA_SIG *sig = NULL;
                    130:        u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL;
                    131:        size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
                    132:        int ret = SSH_ERR_INTERNAL_ERROR;
                    133:        struct sshbuf *b = NULL;
                    134:        char *ktype = NULL;
                    135:
                    136:        if (key == NULL || key->dsa == NULL ||
                    137:            sshkey_type_plain(key->type) != KEY_DSA)
                    138:                return SSH_ERR_INVALID_ARGUMENT;
                    139:        if (dlen == 0)
                    140:                return SSH_ERR_INTERNAL_ERROR;
1.1       markus    141:
                    142:        /* fetch signature */
1.32      djm       143:        if (compat & SSH_BUG_SIGBLOB) {
                    144:                if ((sigblob = malloc(signaturelen)) == NULL)
                    145:                        return SSH_ERR_ALLOC_FAIL;
1.19      jakob     146:                memcpy(sigblob, signature, signaturelen);
1.1       markus    147:                len = signaturelen;
                    148:        } else {
                    149:                /* ietf-drafts */
1.32      djm       150:                if ((b = sshbuf_from(signature, signaturelen)) == NULL)
                    151:                        return SSH_ERR_ALLOC_FAIL;
                    152:                if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
                    153:                    sshbuf_get_string(b, &sigblob, &len) != 0) {
                    154:                        ret = SSH_ERR_INVALID_FORMAT;
                    155:                        goto out;
                    156:                }
1.1       markus    157:                if (strcmp("ssh-dss", ktype) != 0) {
1.32      djm       158:                        ret = SSH_ERR_KEY_TYPE_MISMATCH;
                    159:                        goto out;
1.1       markus    160:                }
1.32      djm       161:                if (sshbuf_len(b) != 0) {
                    162:                        ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
                    163:                        goto out;
1.1       markus    164:                }
                    165:        }
                    166:
                    167:        if (len != SIGBLOB_LEN) {
1.32      djm       168:                ret = SSH_ERR_INVALID_FORMAT;
                    169:                goto out;
1.1       markus    170:        }
                    171:
                    172:        /* parse signature */
1.32      djm       173:        if ((sig = DSA_SIG_new()) == NULL ||
                    174:            (sig->r = BN_new()) == NULL ||
                    175:            (sig->s = BN_new()) == NULL) {
                    176:                ret = SSH_ERR_ALLOC_FAIL;
                    177:                goto out;
                    178:        }
1.24      markus    179:        if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) ||
1.32      djm       180:            (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) {
                    181:                ret = SSH_ERR_LIBCRYPTO_ERROR;
                    182:                goto out;
                    183:        }
1.5       stevesk   184:
1.1       markus    185:        /* sha1 the data */
1.32      djm       186:        if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
                    187:            digest, sizeof(digest))) != 0)
                    188:                goto out;
                    189:
                    190:        switch (DSA_do_verify(digest, dlen, sig, key->dsa)) {
                    191:        case 1:
                    192:                ret = 0;
                    193:                break;
                    194:        case 0:
                    195:                ret = SSH_ERR_SIGNATURE_INVALID;
                    196:                goto out;
                    197:        default:
                    198:                ret = SSH_ERR_LIBCRYPTO_ERROR;
                    199:                goto out;
1.30      djm       200:        }
1.1       markus    201:
1.32      djm       202:  out:
1.31      djm       203:        explicit_bzero(digest, sizeof(digest));
1.32      djm       204:        if (sig != NULL)
                    205:                DSA_SIG_free(sig);
                    206:        if (b != NULL)
                    207:                sshbuf_free(b);
1.33    ! mmcc      208:        free(ktype);
1.32      djm       209:        if (sigblob != NULL) {
                    210:                explicit_bzero(sigblob, len);
                    211:                free(sigblob);
                    212:        }
1.1       markus    213:        return ret;
                    214: }