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

1.1     ! marius      1: /* $OpenBSD$ */
        !             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:
        !            56: struct des3_state {
        !            57:        des_key_schedule        k1, k2, k3;
        !            58:        des_cblock              iv1, iv2, iv3;
        !            59: };
        !            60:
        !            61: static int
        !            62: get_bn(BIGNUM *bn, u_char **pp, int *lenp)
        !            63: {
        !            64:        short i;
        !            65:
        !            66:        if (*lenp < 2) {
        !            67:                errno = EINVAL;
        !            68:                return (-1);
        !            69:        }
        !            70:        GETSHORT(i, *pp); *lenp -= 2;
        !            71:
        !            72:        i = ((i + 7) / 8);
        !            73:
        !            74:        if (*lenp < i) {
        !            75:                errno = EINVAL;
        !            76:                return (-1);
        !            77:        }
        !            78:        BN_bin2bn(*pp, i, bn);
        !            79:
        !            80:        *pp += i; *lenp -= i;
        !            81:
        !            82:        return (0);
        !            83: }
        !            84:
        !            85: static int
        !            86: get_string(char *dst, int len, u_char **pp, int *lenp)
        !            87: {
        !            88:        long i;
        !            89:
        !            90:        if (*lenp < 4) {
        !            91:                errno = EINVAL;
        !            92:                return (-1);
        !            93:        }
        !            94:        GETLONG(i, *pp); *lenp -= 4;
        !            95:
        !            96:        if (*lenp < i || len < i) {
        !            97:                errno = EINVAL;
        !            98:                return (-1);
        !            99:        }
        !           100:        memcpy(dst, *pp, i);
        !           101:
        !           102:        *pp += i; *lenp -= i;
        !           103:
        !           104:        return (0);
        !           105: }
        !           106:
        !           107: static int
        !           108: read_ssh1_bn(BIGNUM *value, char **cpp)
        !           109: {
        !           110:        char *cp = *cpp;
        !           111:        int old;
        !           112:
        !           113:        /* Skip any leading whitespace. */
        !           114:        for (; *cp == ' ' || *cp == '\t'; cp++)
        !           115:                ;
        !           116:
        !           117:        /* Check that it begins with a decimal digit. */
        !           118:        if (*cp < '0' || *cp > '9') {
        !           119:                errno = EINVAL;
        !           120:                return (-1);
        !           121:        }
        !           122:        /* Save starting position. */
        !           123:        *cpp = cp;
        !           124:
        !           125:        /* Move forward until all decimal digits skipped. */
        !           126:        for (; *cp >= '0' && *cp <= '9'; cp++)
        !           127:                ;
        !           128:
        !           129:        /* Save the old terminating character, and replace it by \0. */
        !           130:        old = *cp;
        !           131:        *cp = 0;
        !           132:
        !           133:        /* Parse the number. */
        !           134:        if (BN_dec2bn(&value, *cpp) == 0)
        !           135:                return (-1);
        !           136:
        !           137:        /* Restore old terminating character. */
        !           138:        *cp = old;
        !           139:
        !           140:        /* Move beyond the number and return success. */
        !           141:        *cpp = cp;
        !           142:        return (0);
        !           143: }
        !           144:
        !           145: /* XXX - SSH1's weirdo 3DES... */
        !           146: static void *
        !           147: des3_init(u_char *sesskey, int len)
        !           148: {
        !           149:        struct des3_state *state;
        !           150:
        !           151:        if ((state = malloc(sizeof(*state))) == NULL)
        !           152:                return (NULL);
        !           153:
        !           154:        des_set_key((void *)sesskey, state->k1);
        !           155:        des_set_key((void *)(sesskey + 8), state->k2);
        !           156:
        !           157:        if (len <= 16)
        !           158:                des_set_key((void *)sesskey, state->k3);
        !           159:        else
        !           160:                des_set_key((void *)(sesskey + 16), state->k3);
        !           161:
        !           162:        memset(state->iv1, 0, 8);
        !           163:        memset(state->iv2, 0, 8);
        !           164:        memset(state->iv3, 0, 8);
        !           165:
        !           166:        return (state);
        !           167: }
        !           168:
        !           169: static void
        !           170: des3_decrypt(u_char *src, u_char *dst, int len, void *state)
        !           171: {
        !           172:        struct des3_state *dstate;
        !           173:
        !           174:        dstate = (struct des3_state *)state;
        !           175:        memcpy(dstate->iv1, dstate->iv2, 8);
        !           176:
        !           177:        des_ncbc_encrypt(src, dst, len, dstate->k3, &dstate->iv3, DES_DECRYPT);
        !           178:        des_ncbc_encrypt(dst, dst, len, dstate->k2, &dstate->iv2, DES_ENCRYPT);
        !           179:        des_ncbc_encrypt(dst, dst, len, dstate->k1, &dstate->iv1, DES_DECRYPT);
        !           180: }
        !           181:
        !           182: static int
        !           183: load_ssh1_public(RSA *rsa, struct iovec *iov)
        !           184: {
        !           185:        char *p;
        !           186:        u_int bits;
        !           187:
        !           188:        /* Skip leading whitespace. */
        !           189:        for (p = iov->iov_base; *p == ' ' || *p == '\t'; p++)
        !           190:                ;
        !           191:
        !           192:        /* Get number of bits. */
        !           193:        if (*p < '0' || *p > '9')
        !           194:                return (-1);
        !           195:
        !           196:        for (bits = 0; *p >= '0' && *p <= '9'; p++)
        !           197:                bits = 10 * bits + *p - '0';
        !           198:
        !           199:        if (bits == 0)
        !           200:                return (-1);
        !           201:
        !           202:        /* Get public exponent, public modulus. */
        !           203:        if (read_ssh1_bn(rsa->e, &p) < 0)
        !           204:                return (-1);
        !           205:
        !           206:        if (read_ssh1_bn(rsa->n, &p) < 0)
        !           207:                return (-1);
        !           208:
        !           209:        return (0);
        !           210: }
        !           211:
        !           212: static int
        !           213: load_ssh1_private(RSA *rsa, struct iovec *iov)
        !           214: {
        !           215:        BN_CTX *ctx;
        !           216:        BIGNUM *aux;
        !           217:        MD5_CTX md;
        !           218:        char pass[128], prompt[128], comment[BUFSIZ];
        !           219:        u_char *p, cipher_type, digest[16];
        !           220:        void *dstate;
        !           221:        int i;
        !           222:
        !           223:        i = strlen(SSH1_MAGIC) + 1;
        !           224:
        !           225:        /* Make sure it begins with the id string. */
        !           226:        if (iov->iov_len < i || memcmp(iov->iov_base, SSH1_MAGIC, i) != 0)
        !           227:                return (-1);
        !           228:
        !           229:        p = (u_char *)iov->iov_base + i;
        !           230:        i = iov->iov_len - i;
        !           231:
        !           232:        /* Skip cipher_type, reserved data, bits. */
        !           233:        cipher_type = *p;
        !           234:        p += 1 + 4 + 4;
        !           235:        i -= 1 + 4 + 4;
        !           236:
        !           237:        /* Read public key. */
        !           238:        if (get_bn(rsa->n, &p, &i) < 0 || get_bn(rsa->e, &p, &i) < 0)
        !           239:                return (-1);
        !           240:
        !           241:        /* Read comment. */
        !           242:        if (get_string(comment, sizeof(comment), &p, &i) < 0)
        !           243:                return (-1);
        !           244:
        !           245:        /* Decrypt private key. */
        !           246:        if (cipher_type != 0) {
        !           247:                sign_passwd_cb(pass, sizeof(pass), 0, NULL);
        !           248:
        !           249:                MD5_Init(&md);
        !           250:                MD5_Update(&md, (const u_char *)pass, strlen(pass));
        !           251:                MD5_Final(digest, &md);
        !           252:
        !           253:                memset(pass, 0, strlen(pass));
        !           254:
        !           255:                if ((dstate = des3_init(digest, sizeof(digest))) == NULL)
        !           256:                        return (-1);
        !           257:
        !           258:                des3_decrypt(p, p, i, dstate);
        !           259:
        !           260:                if (p[0] != p[2] || p[1] != p[3]) {
        !           261:                        fprintf(stderr, "Bad passphrase for %s\n", comment);
        !           262:                        return (-1);
        !           263:                }
        !           264:        }
        !           265:        else if (p[0] != p[2] || p[1] != p[3])
        !           266:                return (-1);
        !           267:
        !           268:        p += 4;
        !           269:        i -= 4;
        !           270:
        !           271:        /* Read the private key. */
        !           272:        if (get_bn(rsa->d, &p, &i) < 0 ||
        !           273:            get_bn(rsa->iqmp, &p, &i) < 0)
        !           274:                return (-1);
        !           275:
        !           276:        /* In SSL and SSH v1 p and q are exchanged. */
        !           277:        if (get_bn(rsa->q, &p, &i) < 0 ||
        !           278:            get_bn(rsa->p, &p, &i) < 0)
        !           279:                return (-1);
        !           280:
        !           281:        /* Calculate p-1 and q-1. */
        !           282:        ctx = BN_CTX_new();
        !           283:        aux = BN_new();
        !           284:
        !           285:        BN_sub(aux, rsa->q, BN_value_one());
        !           286:        BN_mod(rsa->dmq1, rsa->d, aux, ctx);
        !           287:
        !           288:        BN_sub(aux, rsa->p, BN_value_one());
        !           289:        BN_mod(rsa->dmp1, rsa->d, aux, ctx);
        !           290:
        !           291:        BN_clear_free(aux);
        !           292:        BN_CTX_free(ctx);
        !           293:
        !           294:        return (0);
        !           295: }
        !           296:
        !           297: int
        !           298: ssh_load_public(struct key *k, struct iovec *iov)
        !           299: {
        !           300:        RSA *rsa;
        !           301:
        !           302:        rsa = RSA_new();
        !           303:
        !           304:        rsa->n = BN_new();
        !           305:        rsa->e = BN_new();
        !           306:
        !           307:        if (load_ssh1_public(rsa, iov) < 0) {
        !           308:                RSA_free(rsa);
        !           309:                return (-1);
        !           310:        }
        !           311:        k->type = KEY_RSA;
        !           312:        k->data = (void *)rsa;
        !           313:
        !           314:        return (0);
        !           315: }
        !           316:
        !           317: int
        !           318: ssh_load_private(struct key *k, struct iovec *iov)
        !           319: {
        !           320:        RSA *rsa;
        !           321:
        !           322:        rsa = RSA_new();
        !           323:
        !           324:        rsa->n = BN_new();
        !           325:        rsa->e = BN_new();
        !           326:
        !           327:        rsa->d = BN_new();
        !           328:        rsa->iqmp = BN_new();
        !           329:        rsa->q = BN_new();
        !           330:        rsa->p = BN_new();
        !           331:        rsa->dmq1 = BN_new();
        !           332:        rsa->dmp1 = BN_new();
        !           333:
        !           334:        if (load_ssh1_private(rsa, iov) < 0) {
        !           335:                RSA_free(rsa);
        !           336:                return (-1);
        !           337:
        !           338:        }
        !           339:        k->type = KEY_RSA;
        !           340:        k->data = (void *)rsa;
        !           341:
        !           342:        return (0);
        !           343: }