[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.32

1.32    ! djm         1: /* $OpenBSD: ssh-dss.c,v 1.31 2014/02/02 03:44:31 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);
        !           208:        if (ktype != NULL)
        !           209:                free(ktype);
        !           210:        if (sigblob != NULL) {
        !           211:                explicit_bzero(sigblob, len);
        !           212:                free(sigblob);
        !           213:        }
1.1       markus    214:        return ret;
                    215: }