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

Annotation of src/usr.bin/gzsig/ssh.c, Revision 1.3

1.3     ! miod        1: /* $OpenBSD: ssh.c,v 1.2 2005/05/29 09:10:23 djm Exp $ */
1.1       marius      2:
                      3: /*
                      4:  * ssh.c
                      5:  *
                      6:  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
                      7:  * Copyright (c) 2000 Niels Provos <provos@monkey.org>
                      8:  * Copyright (c) 2000 Markus Friedl <markus@monkey.org>
                      9:  *
                     10:  *   Redistribution and use in source and binary forms, with or without
                     11:  *   modification, are permitted provided that the following conditions
                     12:  *   are met:
                     13:  *
                     14:  *   1. Redistributions of source code must retain the above copyright
                     15:  *      notice, this list of conditions and the following disclaimer.
                     16:  *   2. Redistributions in binary form must reproduce the above copyright
                     17:  *      notice, this list of conditions and the following disclaimer in the
                     18:  *      documentation and/or other materials provided with the distribution.
                     19:  *   3. The names of the copyright holders may not be used to endorse or
                     20:  *      promote products derived from this software without specific
                     21:  *      prior written permission.
                     22:  *
                     23:  *   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     24:  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     25:  *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
                     26:  *   THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     27:  *   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     28:  *   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     29:  *   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     30:  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     31:  *   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     32:  *   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     33:  *
                     34:  * $Vendor: ssh.c,v 1.2 2005/04/01 16:47:31 dugsong Exp $
                     35:  */
                     36:
                     37: #include <sys/types.h>
                     38: #include <sys/uio.h>
                     39:
                     40: #include <arpa/nameser.h>
                     41: #include <openssl/ssl.h>
                     42: #include <openssl/des.h>
                     43: #include <openssl/md5.h>
                     44:
                     45: #include <errno.h>
                     46: #include <stdio.h>
                     47: #include <stdlib.h>
                     48: #include <string.h>
                     49: #include <unistd.h>
                     50:
                     51: #include "key.h"
                     52: #include "ssh.h"
                     53:
                     54: #define SSH1_MAGIC             "SSH PRIVATE KEY FILE FORMAT 1.1\n"
                     55:
1.2       djm        56: extern int sign_passwd_cb(char *, int, int, void *);
                     57:
1.1       marius     58: struct des3_state {
1.3     ! miod       59:        DES_key_schedule        k1, k2, k3;
        !            60:        DES_cblock              iv1, iv2, iv3;
1.1       marius     61: };
                     62:
                     63: static int
                     64: get_bn(BIGNUM *bn, u_char **pp, int *lenp)
                     65: {
                     66:        short i;
                     67:
                     68:        if (*lenp < 2) {
                     69:                errno = EINVAL;
                     70:                return (-1);
                     71:        }
                     72:        GETSHORT(i, *pp); *lenp -= 2;
                     73:
                     74:        i = ((i + 7) / 8);
                     75:
                     76:        if (*lenp < i) {
                     77:                errno = EINVAL;
                     78:                return (-1);
                     79:        }
                     80:        BN_bin2bn(*pp, i, bn);
                     81:
                     82:        *pp += i; *lenp -= i;
                     83:
                     84:        return (0);
                     85: }
                     86:
                     87: static int
                     88: get_string(char *dst, int len, u_char **pp, int *lenp)
                     89: {
                     90:        long i;
                     91:
                     92:        if (*lenp < 4) {
                     93:                errno = EINVAL;
                     94:                return (-1);
                     95:        }
                     96:        GETLONG(i, *pp); *lenp -= 4;
                     97:
                     98:        if (*lenp < i || len < i) {
                     99:                errno = EINVAL;
                    100:                return (-1);
                    101:        }
                    102:        memcpy(dst, *pp, i);
                    103:
                    104:        *pp += i; *lenp -= i;
                    105:
                    106:        return (0);
                    107: }
                    108:
                    109: static int
                    110: read_ssh1_bn(BIGNUM *value, char **cpp)
                    111: {
                    112:        char *cp = *cpp;
                    113:        int old;
                    114:
                    115:        /* Skip any leading whitespace. */
                    116:        for (; *cp == ' ' || *cp == '\t'; cp++)
                    117:                ;
                    118:
                    119:        /* Check that it begins with a decimal digit. */
                    120:        if (*cp < '0' || *cp > '9') {
                    121:                errno = EINVAL;
                    122:                return (-1);
                    123:        }
                    124:        /* Save starting position. */
                    125:        *cpp = cp;
                    126:
                    127:        /* Move forward until all decimal digits skipped. */
                    128:        for (; *cp >= '0' && *cp <= '9'; cp++)
                    129:                ;
                    130:
                    131:        /* Save the old terminating character, and replace it by \0. */
                    132:        old = *cp;
                    133:        *cp = 0;
                    134:
                    135:        /* Parse the number. */
                    136:        if (BN_dec2bn(&value, *cpp) == 0)
                    137:                return (-1);
                    138:
                    139:        /* Restore old terminating character. */
                    140:        *cp = old;
                    141:
                    142:        /* Move beyond the number and return success. */
                    143:        *cpp = cp;
                    144:        return (0);
                    145: }
                    146:
                    147: /* XXX - SSH1's weirdo 3DES... */
                    148: static void *
                    149: des3_init(u_char *sesskey, int len)
                    150: {
                    151:        struct des3_state *state;
                    152:
                    153:        if ((state = malloc(sizeof(*state))) == NULL)
                    154:                return (NULL);
                    155:
1.3     ! miod      156:        DES_set_key((const_DES_cblock *)sesskey, &state->k1);
        !           157:        DES_set_key((const_DES_cblock *)(sesskey + 8), &state->k2);
1.1       marius    158:
                    159:        if (len <= 16)
1.3     ! miod      160:                DES_set_key((const_DES_cblock *)sesskey, &state->k3);
1.1       marius    161:        else
1.3     ! miod      162:                DES_set_key((const_DES_cblock *)(sesskey + 16), &state->k3);
1.1       marius    163:
                    164:        memset(state->iv1, 0, 8);
                    165:        memset(state->iv2, 0, 8);
                    166:        memset(state->iv3, 0, 8);
                    167:
                    168:        return (state);
                    169: }
                    170:
                    171: static void
                    172: des3_decrypt(u_char *src, u_char *dst, int len, void *state)
                    173: {
                    174:        struct des3_state *dstate;
                    175:
                    176:        dstate = (struct des3_state *)state;
                    177:        memcpy(dstate->iv1, dstate->iv2, 8);
                    178:
1.3     ! miod      179:        DES_ncbc_encrypt(src, dst, len, &dstate->k3, &dstate->iv3, DES_DECRYPT);
        !           180:        DES_ncbc_encrypt(dst, dst, len, &dstate->k2, &dstate->iv2, DES_ENCRYPT);
        !           181:        DES_ncbc_encrypt(dst, dst, len, &dstate->k1, &dstate->iv1, DES_DECRYPT);
1.1       marius    182: }
                    183:
                    184: static int
                    185: load_ssh1_public(RSA *rsa, struct iovec *iov)
                    186: {
                    187:        char *p;
                    188:        u_int bits;
                    189:
                    190:        /* Skip leading whitespace. */
                    191:        for (p = iov->iov_base; *p == ' ' || *p == '\t'; p++)
                    192:                ;
                    193:
                    194:        /* Get number of bits. */
                    195:        if (*p < '0' || *p > '9')
                    196:                return (-1);
                    197:
                    198:        for (bits = 0; *p >= '0' && *p <= '9'; p++)
                    199:                bits = 10 * bits + *p - '0';
                    200:
                    201:        if (bits == 0)
                    202:                return (-1);
                    203:
                    204:        /* Get public exponent, public modulus. */
                    205:        if (read_ssh1_bn(rsa->e, &p) < 0)
                    206:                return (-1);
                    207:
                    208:        if (read_ssh1_bn(rsa->n, &p) < 0)
                    209:                return (-1);
                    210:
                    211:        return (0);
                    212: }
                    213:
                    214: static int
                    215: load_ssh1_private(RSA *rsa, struct iovec *iov)
                    216: {
                    217:        BN_CTX *ctx;
                    218:        BIGNUM *aux;
                    219:        MD5_CTX md;
1.2       djm       220:        char pass[128], comment[BUFSIZ];
1.1       marius    221:        u_char *p, cipher_type, digest[16];
                    222:        void *dstate;
                    223:        int i;
                    224:
                    225:        i = strlen(SSH1_MAGIC) + 1;
                    226:
                    227:        /* Make sure it begins with the id string. */
                    228:        if (iov->iov_len < i || memcmp(iov->iov_base, SSH1_MAGIC, i) != 0)
                    229:                return (-1);
                    230:
                    231:        p = (u_char *)iov->iov_base + i;
                    232:        i = iov->iov_len - i;
                    233:
                    234:        /* Skip cipher_type, reserved data, bits. */
                    235:        cipher_type = *p;
                    236:        p += 1 + 4 + 4;
                    237:        i -= 1 + 4 + 4;
                    238:
                    239:        /* Read public key. */
                    240:        if (get_bn(rsa->n, &p, &i) < 0 || get_bn(rsa->e, &p, &i) < 0)
                    241:                return (-1);
                    242:
                    243:        /* Read comment. */
                    244:        if (get_string(comment, sizeof(comment), &p, &i) < 0)
                    245:                return (-1);
                    246:
                    247:        /* Decrypt private key. */
                    248:        if (cipher_type != 0) {
                    249:                sign_passwd_cb(pass, sizeof(pass), 0, NULL);
                    250:
                    251:                MD5_Init(&md);
                    252:                MD5_Update(&md, (const u_char *)pass, strlen(pass));
                    253:                MD5_Final(digest, &md);
                    254:
                    255:                memset(pass, 0, strlen(pass));
                    256:
                    257:                if ((dstate = des3_init(digest, sizeof(digest))) == NULL)
                    258:                        return (-1);
                    259:
                    260:                des3_decrypt(p, p, i, dstate);
                    261:
                    262:                if (p[0] != p[2] || p[1] != p[3]) {
                    263:                        fprintf(stderr, "Bad passphrase for %s\n", comment);
                    264:                        return (-1);
                    265:                }
                    266:        }
                    267:        else if (p[0] != p[2] || p[1] != p[3])
                    268:                return (-1);
                    269:
                    270:        p += 4;
                    271:        i -= 4;
                    272:
                    273:        /* Read the private key. */
                    274:        if (get_bn(rsa->d, &p, &i) < 0 ||
                    275:            get_bn(rsa->iqmp, &p, &i) < 0)
                    276:                return (-1);
                    277:
                    278:        /* In SSL and SSH v1 p and q are exchanged. */
                    279:        if (get_bn(rsa->q, &p, &i) < 0 ||
                    280:            get_bn(rsa->p, &p, &i) < 0)
                    281:                return (-1);
                    282:
                    283:        /* Calculate p-1 and q-1. */
                    284:        ctx = BN_CTX_new();
                    285:        aux = BN_new();
                    286:
                    287:        BN_sub(aux, rsa->q, BN_value_one());
                    288:        BN_mod(rsa->dmq1, rsa->d, aux, ctx);
                    289:
                    290:        BN_sub(aux, rsa->p, BN_value_one());
                    291:        BN_mod(rsa->dmp1, rsa->d, aux, ctx);
                    292:
                    293:        BN_clear_free(aux);
                    294:        BN_CTX_free(ctx);
                    295:
                    296:        return (0);
                    297: }
                    298:
                    299: int
                    300: ssh_load_public(struct key *k, struct iovec *iov)
                    301: {
                    302:        RSA *rsa;
                    303:
                    304:        rsa = RSA_new();
                    305:
                    306:        rsa->n = BN_new();
                    307:        rsa->e = BN_new();
                    308:
                    309:        if (load_ssh1_public(rsa, iov) < 0) {
                    310:                RSA_free(rsa);
                    311:                return (-1);
                    312:        }
                    313:        k->type = KEY_RSA;
                    314:        k->data = (void *)rsa;
                    315:
                    316:        return (0);
                    317: }
                    318:
                    319: int
                    320: ssh_load_private(struct key *k, struct iovec *iov)
                    321: {
                    322:        RSA *rsa;
                    323:
                    324:        rsa = RSA_new();
                    325:
                    326:        rsa->n = BN_new();
                    327:        rsa->e = BN_new();
                    328:
                    329:        rsa->d = BN_new();
                    330:        rsa->iqmp = BN_new();
                    331:        rsa->q = BN_new();
                    332:        rsa->p = BN_new();
                    333:        rsa->dmq1 = BN_new();
                    334:        rsa->dmp1 = BN_new();
                    335:
                    336:        if (load_ssh1_private(rsa, iov) < 0) {
                    337:                RSA_free(rsa);
                    338:                return (-1);
                    339:
                    340:        }
                    341:        k->type = KEY_RSA;
                    342:        k->data = (void *)rsa;
                    343:
                    344:        return (0);
                    345: }