diff -urP --exclude-from=../exclude.list ssh/auth2-pubkey.c ssh+x509c/auth2-pubkey.c --- ssh/auth2-pubkey.c Fri May 31 14:35:15 2002 +++ ssh+x509c/auth2-pubkey.c Mon Jun 24 20:54:57 2002 @@ -40,6 +40,7 @@ #include "auth-options.h" #include "canohost.h" #include "monitor_wrap.h" +#include "ssh-x509.h" /* import */ extern ServerOptions options; @@ -82,7 +83,12 @@ pkalg); goto done; } - key = key_from_blob(pkblob, blen); + if (pktype == KEY_X509_RSA || pktype == KEY_X509_DSA) { + key = x509key_from_blob(pkblob, blen); + } + else { + key = key_from_blob(pkblob, blen); + } if (key == NULL) { error("userauth_pubkey: cannot decode key: %s", pkalg); goto done; diff -urP --exclude-from=../exclude.list ssh/authfile.c ssh+x509c/authfile.c --- ssh/authfile.c Thu May 23 22:24:30 2002 +++ ssh+x509c/authfile.c Mon Jun 24 20:52:33 2002 @@ -51,6 +51,7 @@ #include "log.h" #include "authfile.h" #include "rsa.h" +#include "ssh-x509.h" /* Version identification string for SSH v1 identity files. */ static const char authfile_id_string[] = @@ -195,6 +196,10 @@ success = PEM_write_RSAPrivateKey(fp, key->rsa, cipher, passphrase, len, NULL, NULL); break; + case KEY_X509_RSA: + case KEY_X509_DSA: + success = x509key_save_pem(fp, key, cipher, passphrase, len); + break; } fclose(fp); return success; @@ -211,6 +216,8 @@ break; case KEY_DSA: case KEY_RSA: + case KEY_X509_RSA: + case KEY_X509_DSA: return key_save_private_pem(key, filename, passphrase, comment); break; @@ -430,6 +437,7 @@ Key *prv = NULL; char *name = ""; + debug("read PEM private key begin"); fp = fdopen(fd, "r"); if (fp == NULL) { error("fdopen failed: %s", strerror(errno)); @@ -462,6 +470,8 @@ error("PEM_read_PrivateKey: mismatch or " "unknown EVP_PKEY save_type %d", pk->save_type); } + if (prv) + x509key_load_cert(prv, fp); fclose(fp); if (pk != NULL) EVP_PKEY_free(pk); @@ -604,6 +614,7 @@ Key *pub; char file[MAXPATHLEN]; + debug3("key_load_public(%.200s,...)", filename); pub = key_load_public_type(KEY_RSA1, filename, commentp); if (pub != NULL) return pub; diff -urP --exclude-from=../exclude.list ssh/key.c ssh+x509c/key.c --- ssh/key.c Fri May 31 16:16:48 2002 +++ ssh+x509c/key.c Mon Jun 24 21:06:22 2002 @@ -41,6 +41,7 @@ #include "rsa.h" #include "ssh-dss.h" #include "ssh-rsa.h" +#include "ssh-x509.h" #include "uuencode.h" #include "buffer.h" #include "bufaux.h" @@ -57,6 +58,7 @@ k->flags = 0; k->dsa = NULL; k->rsa = NULL; + k->x509 = NULL; switch (k->type) { case KEY_RSA1: case KEY_RSA: @@ -81,6 +83,11 @@ fatal("key_new: BN_new failed"); k->dsa = dsa; break; + case KEY_X509_RSA: + case KEY_X509_DSA: + k->x509 = X509_new(); + debug ("key_new: KEY_X509_XXX - more ... ?"); + break; case KEY_UNSPEC: break; default: @@ -135,6 +142,21 @@ DSA_free(k->dsa); k->dsa = NULL; break; + case KEY_X509_RSA: + case KEY_X509_DSA: + if (k->dsa != NULL) { + DSA_free(k->dsa); + k->dsa = NULL; + } + if (k->rsa != NULL) { + RSA_free(k->rsa); + k->rsa = NULL; + } + if (k->x509 != NULL) { + X509_free(k->x509); + k->x509 = NULL; + } + break; case KEY_UNSPEC: break; default: @@ -149,12 +171,24 @@ if (a == NULL || b == NULL || a->type != b->type) return 0; switch (a->type) { + case KEY_X509_RSA: + if(a->rsa == NULL || b->rsa == NULL) { + return X509_subject_name_cmp(a->x509, b->x509) == 0; + break; + } + /* no break !!!*/ case KEY_RSA1: case KEY_RSA: return a->rsa != NULL && b->rsa != NULL && BN_cmp(a->rsa->e, b->rsa->e) == 0 && BN_cmp(a->rsa->n, b->rsa->n) == 0; break; + case KEY_X509_DSA: + if(a->dsa == NULL || b->dsa == NULL) { + return X509_subject_name_cmp(a->x509, b->x509) == 0; + break; + } + /* no break !!!*/ case KEY_DSA: return a->dsa != NULL && b->dsa != NULL && BN_cmp(a->dsa->p, b->dsa->p) == 0 && @@ -203,6 +237,8 @@ break; case KEY_DSA: case KEY_RSA: + case KEY_X509_RSA: /*XXX*/ + case KEY_X509_DSA: /*XXX*/ key_to_blob(k, &blob, &len); break; case KEY_UNSPEC: @@ -405,6 +441,8 @@ case KEY_UNSPEC: case KEY_RSA: case KEY_DSA: + case KEY_X509_RSA: + case KEY_X509_DSA: space = strchr(cp, ' '); if (space == NULL) { debug3("key_read: no space"); @@ -429,6 +467,9 @@ debug3("key_read: type mismatch"); return -1; } + k = x509key_from_subject(type, cp); + if(k != NULL) + goto noblob; len = 2*strlen(cp); blob = xmalloc(len); n = uudecode(cp, blob, len); @@ -437,7 +478,12 @@ xfree(blob); return -1; } - k = key_from_blob(blob, n); + if (type == KEY_X509_RSA || + type == KEY_X509_DSA) { + k = x509key_from_blob(blob, n); + } + else + k = key_from_blob(blob, n); xfree(blob); if (k == NULL) { error("key_read: key_from_blob %s failed", cp); @@ -448,7 +494,30 @@ key_free(k); return -1; } +noblob: /*XXXX*/ + if (ret->type == KEY_X509_RSA || + ret->type == KEY_X509_DSA ) { + if (ret->rsa != NULL) + RSA_free(ret->rsa); + ret->rsa = k->rsa; + k->rsa = NULL; + if (ret->dsa != NULL) + DSA_free(ret->dsa); + ret->dsa = k->dsa; + k->dsa = NULL; + if (ret->x509 != NULL) + X509_free(ret->x509); + ret->x509 = k->x509; + k->x509 = NULL; +#ifdef DEBUG_PK + if (ret->type == KEY_X509_RSA) + RSA_print_fp(stderr, ret->rsa, 8); + else + DSA_print_fp(stderr, ret->dsa, 8); +#endif + success = 1; + } else if (ret->type == KEY_RSA) { if (ret->rsa != NULL) RSA_free(ret->rsa); @@ -513,6 +582,8 @@ } xfree(blob); xfree(uu); + } else if ( (key->type == KEY_X509_RSA) || (key->type == KEY_X509_DSA) ) { + success = x509key_write(key, f); } return success; } @@ -529,6 +600,14 @@ case KEY_DSA: return "DSA"; break; + case KEY_X509_RSA: + if(k->rsa) return "RSA+cert"; + return "X509(rsa)"; + break; + case KEY_X509_DSA: + if(k->dsa) return "DSA+cert"; + return "X509(dsa)"; + break; } return "unknown"; } @@ -542,6 +621,12 @@ case KEY_DSA: return "ssh-dss"; break; + case KEY_X509_RSA: + return "x509v3-sign-rsa"; + break; + case KEY_X509_DSA: + return "x509v3-sign-dss"; + break; } return "ssh-unknown"; } @@ -630,6 +715,7 @@ int key_type_from_name(char *name) { + debug3("call key_type_from_name(%.200s) ...", name); if (strcmp(name, "rsa1") == 0) { return KEY_RSA1; } else if (strcmp(name, "rsa") == 0) { @@ -640,6 +726,10 @@ return KEY_RSA; } else if (strcmp(name, "ssh-dss") == 0) { return KEY_DSA; + } else if (strcmp(name, "x509v3-sign-rsa") == 0) { + return KEY_X509_RSA; + } else if (strcmp(name, "x509v3-sign-dss") == 0) { + return KEY_X509_DSA; } debug2("key_type_from_name: unknown key type '%s'", name); return KEY_UNSPEC; @@ -674,6 +764,7 @@ char *ktype; int rlen, type; Key *key = NULL; + debug3("key_from_blob(..., %d)", blen); #ifdef DEBUG_PK dump_base64(stderr, blob, blen); @@ -682,6 +773,7 @@ buffer_append(&b, blob, blen); ktype = buffer_get_string(&b, NULL); type = key_type_from_name(ktype); + debug3("key_from_blob(..., ...) ktype=%.30s", ktype); switch (type) { case KEY_RSA: @@ -742,6 +834,11 @@ buffer_put_bignum2(&b, key->rsa->e); buffer_put_bignum2(&b, key->rsa->n); break; + case KEY_X509_RSA: + case KEY_X509_DSA: + if (!x509key_to_blob(key, &b)) + return 0; + break; default: error("key_to_blob: unsupported key type %d", key->type); buffer_free(&b); @@ -772,6 +869,10 @@ case KEY_RSA: return ssh_rsa_sign(key, sigp, lenp, data, datalen); break; + case KEY_X509_RSA: + case KEY_X509_DSA: + return ssh_x509_sign(key, sigp, lenp, data, datalen); + break; default: error("key_sign: illegal key type %d", key->type); return -1; @@ -798,6 +899,10 @@ break; case KEY_RSA: return ssh_rsa_verify(key, signature, signaturelen, data, datalen); + break; + case KEY_X509_RSA: + case KEY_X509_DSA: + return ssh_x509_verify(key, signature, signaturelen, data, datalen); break; default: error("key_verify: illegal key type %d", key->type); diff -urP --exclude-from=../exclude.list ssh/key.c.ORIG ssh+x509c/key.c.ORIG --- ssh/key.c.ORIG Thu Jan 1 02:00:00 1970 +++ ssh+x509c/key.c.ORIG Fri May 31 16:16:48 2002 @@ -0,0 +1,850 @@ +/* + * read_bignum(): + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + * + * + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "includes.h" +RCSID("$OpenBSD: key.c,v 1.44 2002/05/31 13:16:48 markus Exp $"); + +#include + +#include "xmalloc.h" +#include "key.h" +#include "rsa.h" +#include "ssh-dss.h" +#include "ssh-rsa.h" +#include "uuencode.h" +#include "buffer.h" +#include "bufaux.h" +#include "log.h" + +Key * +key_new(int type) +{ + Key *k; + RSA *rsa; + DSA *dsa; + k = xmalloc(sizeof(*k)); + k->type = type; + k->flags = 0; + k->dsa = NULL; + k->rsa = NULL; + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if ((rsa = RSA_new()) == NULL) + fatal("key_new: RSA_new failed"); + if ((rsa->n = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + if ((rsa->e = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + k->rsa = rsa; + break; + case KEY_DSA: + if ((dsa = DSA_new()) == NULL) + fatal("key_new: DSA_new failed"); + if ((dsa->p = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + if ((dsa->q = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + if ((dsa->g = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + if ((dsa->pub_key = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + k->dsa = dsa; + break; + case KEY_UNSPEC: + break; + default: + fatal("key_new: bad key type %d", k->type); + break; + } + return k; +} +Key * +key_new_private(int type) +{ + Key *k = key_new(type); + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if ((k->rsa->d = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->iqmp = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->q = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->p = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->dmq1 = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->dmp1 = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + break; + case KEY_DSA: + if ((k->dsa->priv_key = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + break; + case KEY_UNSPEC: + break; + default: + break; + } + return k; +} +void +key_free(Key *k) +{ + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if (k->rsa != NULL) + RSA_free(k->rsa); + k->rsa = NULL; + break; + case KEY_DSA: + if (k->dsa != NULL) + DSA_free(k->dsa); + k->dsa = NULL; + break; + case KEY_UNSPEC: + break; + default: + fatal("key_free: bad key type %d", k->type); + break; + } + xfree(k); +} +int +key_equal(Key *a, Key *b) +{ + if (a == NULL || b == NULL || a->type != b->type) + return 0; + switch (a->type) { + case KEY_RSA1: + case KEY_RSA: + return a->rsa != NULL && b->rsa != NULL && + BN_cmp(a->rsa->e, b->rsa->e) == 0 && + BN_cmp(a->rsa->n, b->rsa->n) == 0; + break; + case KEY_DSA: + return a->dsa != NULL && b->dsa != NULL && + BN_cmp(a->dsa->p, b->dsa->p) == 0 && + BN_cmp(a->dsa->q, b->dsa->q) == 0 && + BN_cmp(a->dsa->g, b->dsa->g) == 0 && + BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0; + break; + default: + fatal("key_equal: bad key type %d", a->type); + break; + } + return 0; +} + +static u_char* +key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length) +{ + const EVP_MD *md = NULL; + EVP_MD_CTX ctx; + u_char *blob = NULL; + u_char *retval = NULL; + u_int len = 0; + int nlen, elen; + + *dgst_raw_length = 0; + + switch (dgst_type) { + case SSH_FP_MD5: + md = EVP_md5(); + break; + case SSH_FP_SHA1: + md = EVP_sha1(); + break; + default: + fatal("key_fingerprint_raw: bad digest type %d", + dgst_type); + } + switch (k->type) { + case KEY_RSA1: + nlen = BN_num_bytes(k->rsa->n); + elen = BN_num_bytes(k->rsa->e); + len = nlen + elen; + blob = xmalloc(len); + BN_bn2bin(k->rsa->n, blob); + BN_bn2bin(k->rsa->e, blob + nlen); + break; + case KEY_DSA: + case KEY_RSA: + key_to_blob(k, &blob, &len); + break; + case KEY_UNSPEC: + return retval; + break; + default: + fatal("key_fingerprint_raw: bad key type %d", k->type); + break; + } + if (blob != NULL) { + retval = xmalloc(EVP_MAX_MD_SIZE); + EVP_DigestInit(&ctx, md); + EVP_DigestUpdate(&ctx, blob, len); + EVP_DigestFinal(&ctx, retval, dgst_raw_length); + memset(blob, 0, len); + xfree(blob); + } else { + fatal("key_fingerprint_raw: blob is null"); + } + return retval; +} + +static char* +key_fingerprint_hex(u_char* dgst_raw, u_int dgst_raw_len) +{ + char *retval; + int i; + + retval = xmalloc(dgst_raw_len * 3 + 1); + retval[0] = '\0'; + for (i = 0; i < dgst_raw_len; i++) { + char hex[4]; + snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]); + strlcat(retval, hex, dgst_raw_len * 3); + } + retval[(dgst_raw_len * 3) - 1] = '\0'; + return retval; +} + +static char* +key_fingerprint_bubblebabble(u_char* dgst_raw, u_int dgst_raw_len) +{ + char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; + char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', + 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' }; + u_int i, j = 0, rounds, seed = 1; + char *retval; + + rounds = (dgst_raw_len / 2) + 1; + retval = xmalloc(sizeof(char) * (rounds*6)); + retval[j++] = 'x'; + for (i = 0; i < rounds; i++) { + u_int idx0, idx1, idx2, idx3, idx4; + if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) { + idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) + + seed) % 6; + idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15; + idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) + + (seed / 6)) % 6; + retval[j++] = vowels[idx0]; + retval[j++] = consonants[idx1]; + retval[j++] = vowels[idx2]; + if ((i + 1) < rounds) { + idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15; + idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15; + retval[j++] = consonants[idx3]; + retval[j++] = '-'; + retval[j++] = consonants[idx4]; + seed = ((seed * 5) + + ((((u_int)(dgst_raw[2 * i])) * 7) + + ((u_int)(dgst_raw[(2 * i) + 1])))) % 36; + } + } else { + idx0 = seed % 6; + idx1 = 16; + idx2 = seed / 6; + retval[j++] = vowels[idx0]; + retval[j++] = consonants[idx1]; + retval[j++] = vowels[idx2]; + } + } + retval[j++] = 'x'; + retval[j++] = '\0'; + return retval; +} + +char* +key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) +{ + char *retval = NULL; + u_char *dgst_raw; + u_int dgst_raw_len; + + dgst_raw = key_fingerprint_raw(k, dgst_type, &dgst_raw_len); + if (!dgst_raw) + fatal("key_fingerprint: null from key_fingerprint_raw()"); + switch (dgst_rep) { + case SSH_FP_HEX: + retval = key_fingerprint_hex(dgst_raw, dgst_raw_len); + break; + case SSH_FP_BUBBLEBABBLE: + retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len); + break; + default: + fatal("key_fingerprint_ex: bad digest representation %d", + dgst_rep); + break; + } + memset(dgst_raw, 0, dgst_raw_len); + xfree(dgst_raw); + return retval; +} + +/* + * Reads a multiple-precision integer in decimal from the buffer, and advances + * the pointer. The integer must already be initialized. This function is + * permitted to modify the buffer. This leaves *cpp to point just beyond the + * last processed (and maybe modified) character. Note that this may modify + * the buffer containing the number. + */ +static int +read_bignum(char **cpp, BIGNUM * value) +{ + char *cp = *cpp; + int old; + + /* Skip any leading whitespace. */ + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + + /* Check that it begins with a decimal digit. */ + if (*cp < '0' || *cp > '9') + return 0; + + /* Save starting position. */ + *cpp = cp; + + /* Move forward until all decimal digits skipped. */ + for (; *cp >= '0' && *cp <= '9'; cp++) + ; + + /* Save the old terminating character, and replace it by \0. */ + old = *cp; + *cp = 0; + + /* Parse the number. */ + if (BN_dec2bn(&value, *cpp) == 0) + return 0; + + /* Restore old terminating character. */ + *cp = old; + + /* Move beyond the number and return success. */ + *cpp = cp; + return 1; +} +static int +write_bignum(FILE *f, BIGNUM *num) +{ + char *buf = BN_bn2dec(num); + if (buf == NULL) { + error("write_bignum: BN_bn2dec() failed"); + return 0; + } + fprintf(f, " %s", buf); + OPENSSL_free(buf); + return 1; +} + +/* returns 1 ok, -1 error */ +int +key_read(Key *ret, char **cpp) +{ + Key *k; + int success = -1; + char *cp, *space; + int len, n, type; + u_int bits; + u_char *blob; + + cp = *cpp; + + switch (ret->type) { + case KEY_RSA1: + /* Get number of bits. */ + if (*cp < '0' || *cp > '9') + return -1; /* Bad bit count... */ + for (bits = 0; *cp >= '0' && *cp <= '9'; cp++) + bits = 10 * bits + *cp - '0'; + if (bits == 0) + return -1; + *cpp = cp; + /* Get public exponent, public modulus. */ + if (!read_bignum(cpp, ret->rsa->e)) + return -1; + if (!read_bignum(cpp, ret->rsa->n)) + return -1; + success = 1; + break; + case KEY_UNSPEC: + case KEY_RSA: + case KEY_DSA: + space = strchr(cp, ' '); + if (space == NULL) { + debug3("key_read: no space"); + return -1; + } + *space = '\0'; + type = key_type_from_name(cp); + *space = ' '; + if (type == KEY_UNSPEC) { + debug3("key_read: no key found"); + return -1; + } + cp = space+1; + if (*cp == '\0') { + debug3("key_read: short string"); + return -1; + } + if (ret->type == KEY_UNSPEC) { + ret->type = type; + } else if (ret->type != type) { + /* is a key, but different type */ + debug3("key_read: type mismatch"); + return -1; + } + len = 2*strlen(cp); + blob = xmalloc(len); + n = uudecode(cp, blob, len); + if (n < 0) { + error("key_read: uudecode %s failed", cp); + xfree(blob); + return -1; + } + k = key_from_blob(blob, n); + xfree(blob); + if (k == NULL) { + error("key_read: key_from_blob %s failed", cp); + return -1; + } + if (k->type != type) { + error("key_read: type mismatch: encoding error"); + key_free(k); + return -1; + } +/*XXXX*/ + if (ret->type == KEY_RSA) { + if (ret->rsa != NULL) + RSA_free(ret->rsa); + ret->rsa = k->rsa; + k->rsa = NULL; + success = 1; +#ifdef DEBUG_PK + RSA_print_fp(stderr, ret->rsa, 8); +#endif + } else { + if (ret->dsa != NULL) + DSA_free(ret->dsa); + ret->dsa = k->dsa; + k->dsa = NULL; + success = 1; +#ifdef DEBUG_PK + DSA_print_fp(stderr, ret->dsa, 8); +#endif + } +/*XXXX*/ + key_free(k); + if (success != 1) + break; + /* advance cp: skip whitespace and data */ + while (*cp == ' ' || *cp == '\t') + cp++; + while (*cp != '\0' && *cp != ' ' && *cp != '\t') + cp++; + *cpp = cp; + break; + default: + fatal("key_read: bad key type: %d", ret->type); + break; + } + return success; +} +int +key_write(Key *key, FILE *f) +{ + int n, success = 0; + u_int len, bits = 0; + u_char *blob, *uu; + + if (key->type == KEY_RSA1 && key->rsa != NULL) { + /* size of modulus 'n' */ + bits = BN_num_bits(key->rsa->n); + fprintf(f, "%u", bits); + if (write_bignum(f, key->rsa->e) && + write_bignum(f, key->rsa->n)) { + success = 1; + } else { + error("key_write: failed for RSA key"); + } + } else if ((key->type == KEY_DSA && key->dsa != NULL) || + (key->type == KEY_RSA && key->rsa != NULL)) { + key_to_blob(key, &blob, &len); + uu = xmalloc(2*len); + n = uuencode(blob, len, uu, 2*len); + if (n > 0) { + fprintf(f, "%s %s", key_ssh_name(key), uu); + success = 1; + } + xfree(blob); + xfree(uu); + } + return success; +} +char * +key_type(Key *k) +{ + switch (k->type) { + case KEY_RSA1: + return "RSA1"; + break; + case KEY_RSA: + return "RSA"; + break; + case KEY_DSA: + return "DSA"; + break; + } + return "unknown"; +} +char * +key_ssh_name(Key *k) +{ + switch (k->type) { + case KEY_RSA: + return "ssh-rsa"; + break; + case KEY_DSA: + return "ssh-dss"; + break; + } + return "ssh-unknown"; +} +u_int +key_size(Key *k) +{ + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + return BN_num_bits(k->rsa->n); + break; + case KEY_DSA: + return BN_num_bits(k->dsa->p); + break; + } + return 0; +} + +static RSA * +rsa_generate_private_key(u_int bits) +{ + RSA *private; + private = RSA_generate_key(bits, 35, NULL, NULL); + if (private == NULL) + fatal("rsa_generate_private_key: key generation failed."); + return private; +} + +static DSA* +dsa_generate_private_key(u_int bits) +{ + DSA *private = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL); + if (private == NULL) + fatal("dsa_generate_private_key: DSA_generate_parameters failed"); + if (!DSA_generate_key(private)) + fatal("dsa_generate_private_key: DSA_generate_key failed."); + if (private == NULL) + fatal("dsa_generate_private_key: NULL."); + return private; +} + +Key * +key_generate(int type, u_int bits) +{ + Key *k = key_new(KEY_UNSPEC); + switch (type) { + case KEY_DSA: + k->dsa = dsa_generate_private_key(bits); + break; + case KEY_RSA: + case KEY_RSA1: + k->rsa = rsa_generate_private_key(bits); + break; + default: + fatal("key_generate: unknown type %d", type); + } + k->type = type; + return k; +} + +Key * +key_from_private(Key *k) +{ + Key *n = NULL; + switch (k->type) { + case KEY_DSA: + n = key_new(k->type); + BN_copy(n->dsa->p, k->dsa->p); + BN_copy(n->dsa->q, k->dsa->q); + BN_copy(n->dsa->g, k->dsa->g); + BN_copy(n->dsa->pub_key, k->dsa->pub_key); + break; + case KEY_RSA: + case KEY_RSA1: + n = key_new(k->type); + BN_copy(n->rsa->n, k->rsa->n); + BN_copy(n->rsa->e, k->rsa->e); + break; + default: + fatal("key_from_private: unknown type %d", k->type); + break; + } + return n; +} + +int +key_type_from_name(char *name) +{ + if (strcmp(name, "rsa1") == 0) { + return KEY_RSA1; + } else if (strcmp(name, "rsa") == 0) { + return KEY_RSA; + } else if (strcmp(name, "dsa") == 0) { + return KEY_DSA; + } else if (strcmp(name, "ssh-rsa") == 0) { + return KEY_RSA; + } else if (strcmp(name, "ssh-dss") == 0) { + return KEY_DSA; + } + debug2("key_type_from_name: unknown key type '%s'", name); + return KEY_UNSPEC; +} + +int +key_names_valid2(const char *names) +{ + char *s, *cp, *p; + + if (names == NULL || strcmp(names, "") == 0) + return 0; + s = cp = xstrdup(names); + for ((p = strsep(&cp, ",")); p && *p != '\0'; + (p = strsep(&cp, ","))) { + switch (key_type_from_name(p)) { + case KEY_RSA1: + case KEY_UNSPEC: + xfree(s); + return 0; + } + } + debug3("key names ok: [%s]", names); + xfree(s); + return 1; +} + +Key * +key_from_blob(u_char *blob, int blen) +{ + Buffer b; + char *ktype; + int rlen, type; + Key *key = NULL; + +#ifdef DEBUG_PK + dump_base64(stderr, blob, blen); +#endif + buffer_init(&b); + buffer_append(&b, blob, blen); + ktype = buffer_get_string(&b, NULL); + type = key_type_from_name(ktype); + + switch (type) { + case KEY_RSA: + key = key_new(type); + buffer_get_bignum2(&b, key->rsa->e); + buffer_get_bignum2(&b, key->rsa->n); +#ifdef DEBUG_PK + RSA_print_fp(stderr, key->rsa, 8); +#endif + break; + case KEY_DSA: + key = key_new(type); + buffer_get_bignum2(&b, key->dsa->p); + buffer_get_bignum2(&b, key->dsa->q); + buffer_get_bignum2(&b, key->dsa->g); + buffer_get_bignum2(&b, key->dsa->pub_key); +#ifdef DEBUG_PK + DSA_print_fp(stderr, key->dsa, 8); +#endif + break; + case KEY_UNSPEC: + key = key_new(type); + break; + default: + error("key_from_blob: cannot handle type %s", ktype); + break; + } + rlen = buffer_len(&b); + if (key != NULL && rlen != 0) + error("key_from_blob: remaining bytes in key blob %d", rlen); + xfree(ktype); + buffer_free(&b); + return key; +} + +int +key_to_blob(Key *key, u_char **blobp, u_int *lenp) +{ + Buffer b; + int len; + u_char *buf; + + if (key == NULL) { + error("key_to_blob: key == NULL"); + return 0; + } + buffer_init(&b); + switch (key->type) { + case KEY_DSA: + buffer_put_cstring(&b, key_ssh_name(key)); + buffer_put_bignum2(&b, key->dsa->p); + buffer_put_bignum2(&b, key->dsa->q); + buffer_put_bignum2(&b, key->dsa->g); + buffer_put_bignum2(&b, key->dsa->pub_key); + break; + case KEY_RSA: + buffer_put_cstring(&b, key_ssh_name(key)); + buffer_put_bignum2(&b, key->rsa->e); + buffer_put_bignum2(&b, key->rsa->n); + break; + default: + error("key_to_blob: unsupported key type %d", key->type); + buffer_free(&b); + return 0; + } + len = buffer_len(&b); + buf = xmalloc(len); + memcpy(buf, buffer_ptr(&b), len); + memset(buffer_ptr(&b), 0, len); + buffer_free(&b); + if (lenp != NULL) + *lenp = len; + if (blobp != NULL) + *blobp = buf; + return len; +} + +int +key_sign( + Key *key, + u_char **sigp, u_int *lenp, + u_char *data, u_int datalen) +{ + switch (key->type) { + case KEY_DSA: + return ssh_dss_sign(key, sigp, lenp, data, datalen); + break; + case KEY_RSA: + return ssh_rsa_sign(key, sigp, lenp, data, datalen); + break; + default: + error("key_sign: illegal key type %d", key->type); + return -1; + break; + } +} + +/* + * key_verify returns 1 for a correct signature, 0 for an incorrect signature + * and -1 on error. + */ +int +key_verify( + Key *key, + u_char *signature, u_int signaturelen, + u_char *data, u_int datalen) +{ + if (signaturelen == 0) + return -1; + + switch (key->type) { + case KEY_DSA: + return ssh_dss_verify(key, signature, signaturelen, data, datalen); + break; + case KEY_RSA: + return ssh_rsa_verify(key, signature, signaturelen, data, datalen); + break; + default: + error("key_verify: illegal key type %d", key->type); + return -1; + break; + } +} + +/* Converts a private to a public key */ + +Key * +key_demote(Key *k) +{ + Key *pk; + + pk = xmalloc(sizeof(*pk)); + pk->type = k->type; + pk->flags = k->flags; + pk->dsa = NULL; + pk->rsa = NULL; + + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if ((pk->rsa = RSA_new()) == NULL) + fatal("key_demote: RSA_new failed"); + if ((pk->rsa->e = BN_dup(k->rsa->e)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL) + fatal("key_demote: BN_dup failed"); + break; + case KEY_DSA: + if ((pk->dsa = DSA_new()) == NULL) + fatal("key_demote: DSA_new failed"); + if ((pk->dsa->p = BN_dup(k->dsa->p)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->q = BN_dup(k->dsa->q)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->g = BN_dup(k->dsa->g)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) + fatal("key_demote: BN_dup failed"); + break; + default: + fatal("key_free: bad key type %d", k->type); + break; + } + + return (pk); +} diff -urP --exclude-from=../exclude.list ssh/key.c.orig ssh+x509c/key.c.orig --- ssh/key.c.orig Thu Jan 1 02:00:00 1970 +++ ssh+x509c/key.c.orig Mon Jun 24 21:05:37 2002 @@ -0,0 +1,850 @@ +/* + * read_bignum(): + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + * + * + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "includes.h" +RCSID("$OpenBSD: key.c,v 1.44 2002/05/31 13:16:48 markus Exp $"); + +#include + +#include "xmalloc.h" +#include "key.h" +#include "rsa.h" +#include "ssh-dss.h" +#include "ssh-rsa.h" +#include "uuencode.h" +#include "buffer.h" +#include "bufaux.h" +#include "log.h" + +Key * +key_new(int type) +{ + Key *k; + RSA *rsa; + DSA *dsa; + k = xmalloc(sizeof(*k)); + k->type = type; + k->flags = 0; + k->dsa = NULL; + k->rsa = NULL; + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if ((rsa = RSA_new()) == NULL) + fatal("key_new: RSA_new failed"); + if ((rsa->n = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + if ((rsa->e = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + k->rsa = rsa; + break; + case KEY_DSA: + if ((dsa = DSA_new()) == NULL) + fatal("key_new: DSA_new failed"); + if ((dsa->p = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + if ((dsa->q = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + if ((dsa->g = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + if ((dsa->pub_key = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + k->dsa = dsa; + break; + case KEY_UNSPEC: + break; + default: + fatal("key_new: bad key type %d", k->type); + break; + } + return k; +} +Key * +key_new_private(int type) +{ + Key *k = key_new(type); + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if ((k->rsa->d = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->iqmp = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->q = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->p = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->dmq1 = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->dmp1 = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + break; + case KEY_DSA: + if ((k->dsa->priv_key = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + break; + case KEY_UNSPEC: + break; + default: + break; + } + return k; +} +void +key_free(Key *k) +{ + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if (k->rsa != NULL) + RSA_free(k->rsa); + k->rsa = NULL; + break; + case KEY_DSA: + if (k->dsa != NULL) + DSA_free(k->dsa); + k->dsa = NULL; + break; + case KEY_UNSPEC: + break; + default: + fatal("key_free: bad key type %d", k->type); + break; + } + xfree(k); +} +int +key_equal(Key *a, Key *b) +{ + if (a == NULL || b == NULL || a->type != b->type) + return 0; + switch (a->type) { + case KEY_RSA1: + case KEY_RSA: + return a->rsa != NULL && b->rsa != NULL && + BN_cmp(a->rsa->e, b->rsa->e) == 0 && + BN_cmp(a->rsa->n, b->rsa->n) == 0; + break; + case KEY_DSA: + return a->dsa != NULL && b->dsa != NULL && + BN_cmp(a->dsa->p, b->dsa->p) == 0 && + BN_cmp(a->dsa->q, b->dsa->q) == 0 && + BN_cmp(a->dsa->g, b->dsa->g) == 0 && + BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0; + break; + default: + fatal("key_equal: bad key type %d", a->type); + break; + } + return 0; +} + +static u_char* +key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length) +{ + const EVP_MD *md = NULL; + EVP_MD_CTX ctx; + u_char *blob = NULL; + u_char *retval = NULL; + u_int len = 0; + int nlen, elen; + + *dgst_raw_length = 0; + + switch (dgst_type) { + case SSH_FP_MD5: + md = EVP_md5(); + break; + case SSH_FP_SHA1: + md = EVP_sha1(); + break; + default: + fatal("key_fingerprint_raw: bad digest type %d", + dgst_type); + } + switch (k->type) { + case KEY_RSA1: + nlen = BN_num_bytes(k->rsa->n); + elen = BN_num_bytes(k->rsa->e); + len = nlen + elen; + blob = xmalloc(len); + BN_bn2bin(k->rsa->n, blob); + BN_bn2bin(k->rsa->e, blob + nlen); + break; + case KEY_DSA: + case KEY_RSA: + key_to_blob(k, &blob, &len); + break; + case KEY_UNSPEC: + return retval; + break; + default: + fatal("key_fingerprint_raw: bad key type %d", k->type); + break; + } + if (blob != NULL) { + retval = xmalloc(EVP_MAX_MD_SIZE); + EVP_DigestInit(&ctx, md); + EVP_DigestUpdate(&ctx, blob, len); + EVP_DigestFinal(&ctx, retval, dgst_raw_length); + memset(blob, 0, len); + xfree(blob); + } else { + fatal("key_fingerprint_raw: blob is null"); + } + return retval; +} + +static char* +key_fingerprint_hex(u_char* dgst_raw, u_int dgst_raw_len) +{ + char *retval; + int i; + + retval = xmalloc(dgst_raw_len * 3 + 1); + retval[0] = '\0'; + for (i = 0; i < dgst_raw_len; i++) { + char hex[4]; + snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]); + strlcat(retval, hex, dgst_raw_len * 3); + } + retval[(dgst_raw_len * 3) - 1] = '\0'; + return retval; +} + +static char* +key_fingerprint_bubblebabble(u_char* dgst_raw, u_int dgst_raw_len) +{ + char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; + char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', + 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' }; + u_int i, j = 0, rounds, seed = 1; + char *retval; + + rounds = (dgst_raw_len / 2) + 1; + retval = xmalloc(sizeof(char) * (rounds*6)); + retval[j++] = 'x'; + for (i = 0; i < rounds; i++) { + u_int idx0, idx1, idx2, idx3, idx4; + if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) { + idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) + + seed) % 6; + idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15; + idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) + + (seed / 6)) % 6; + retval[j++] = vowels[idx0]; + retval[j++] = consonants[idx1]; + retval[j++] = vowels[idx2]; + if ((i + 1) < rounds) { + idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15; + idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15; + retval[j++] = consonants[idx3]; + retval[j++] = '-'; + retval[j++] = consonants[idx4]; + seed = ((seed * 5) + + ((((u_int)(dgst_raw[2 * i])) * 7) + + ((u_int)(dgst_raw[(2 * i) + 1])))) % 36; + } + } else { + idx0 = seed % 6; + idx1 = 16; + idx2 = seed / 6; + retval[j++] = vowels[idx0]; + retval[j++] = consonants[idx1]; + retval[j++] = vowels[idx2]; + } + } + retval[j++] = 'x'; + retval[j++] = '\0'; + return retval; +} + +char* +key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) +{ + char *retval = NULL; + u_char *dgst_raw; + u_int dgst_raw_len; + + dgst_raw = key_fingerprint_raw(k, dgst_type, &dgst_raw_len); + if (!dgst_raw) + fatal("key_fingerprint: null from key_fingerprint_raw()"); + switch (dgst_rep) { + case SSH_FP_HEX: + retval = key_fingerprint_hex(dgst_raw, dgst_raw_len); + break; + case SSH_FP_BUBBLEBABBLE: + retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len); + break; + default: + fatal("key_fingerprint_ex: bad digest representation %d", + dgst_rep); + break; + } + memset(dgst_raw, 0, dgst_raw_len); + xfree(dgst_raw); + return retval; +} + +/* + * Reads a multiple-precision integer in decimal from the buffer, and advances + * the pointer. The integer must already be initialized. This function is + * permitted to modify the buffer. This leaves *cpp to point just beyond the + * last processed (and maybe modified) character. Note that this may modify + * the buffer containing the number. + */ +static int +read_bignum(char **cpp, BIGNUM * value) +{ + char *cp = *cpp; + int old; + + /* Skip any leading whitespace. */ + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + + /* Check that it begins with a decimal digit. */ + if (*cp < '0' || *cp > '9') + return 0; + + /* Save starting position. */ + *cpp = cp; + + /* Move forward until all decimal digits skipped. */ + for (; *cp >= '0' && *cp <= '9'; cp++) + ; + + /* Save the old terminating character, and replace it by \0. */ + old = *cp; + *cp = 0; + + /* Parse the number. */ + if (BN_dec2bn(&value, *cpp) == 0) + return 0; + + /* Restore old terminating character. */ + *cp = old; + + /* Move beyond the number and return success. */ + *cpp = cp; + return 1; +} +static int +write_bignum(FILE *f, BIGNUM *num) +{ + char *buf = BN_bn2dec(num); + if (buf == NULL) { + error("write_bignum: BN_bn2dec() failed"); + return 0; + } + fprintf(f, " %s", buf); + OPENSSL_free(buf); + return 1; +} + +/* returns 1 ok, -1 error */ +int +key_read(Key *ret, char **cpp) +{ + Key *k; + int success = -1; + char *cp, *space; + int len, n, type; + u_int bits; + u_char *blob; + + cp = *cpp; + + switch (ret->type) { + case KEY_RSA1: + /* Get number of bits. */ + if (*cp < '0' || *cp > '9') + return -1; /* Bad bit count... */ + for (bits = 0; *cp >= '0' && *cp <= '9'; cp++) + bits = 10 * bits + *cp - '0'; + if (bits == 0) + return -1; + *cpp = cp; + /* Get public exponent, public modulus. */ + if (!read_bignum(cpp, ret->rsa->e)) + return -1; + if (!read_bignum(cpp, ret->rsa->n)) + return -1; + success = 1; + break; + case KEY_UNSPEC: + case KEY_RSA: + case KEY_DSA: + space = strchr(cp, ' '); + if (space == NULL) { + debug3("key_read: no space"); + return -1; + } + *space = '\0'; + type = key_type_from_name(cp); + *space = ' '; + if (type == KEY_UNSPEC) { + debug3("key_read: no key found"); + return -1; + } + cp = space+1; + if (*cp == '\0') { + debug3("key_read: short string"); + return -1; + } + if (ret->type == KEY_UNSPEC) { + ret->type = type; + } else if (ret->type != type) { + /* is a key, but different type */ + debug3("key_read: type mismatch"); + return -1; + } + len = 2*strlen(cp); + blob = xmalloc(len); + n = uudecode(cp, blob, len); + if (n < 0) { + error("key_read: uudecode %s failed", cp); + xfree(blob); + return -1; + } + k = key_from_blob(blob, n); + xfree(blob); + if (k == NULL) { + error("key_read: key_from_blob %s failed", cp); + return -1; + } + if (k->type != type) { + error("key_read: type mismatch: encoding error"); + key_free(k); + return -1; + } +/*XXXX*/ + if (ret->type == KEY_RSA) { + if (ret->rsa != NULL) + RSA_free(ret->rsa); + ret->rsa = k->rsa; + k->rsa = NULL; + success = 1; +#ifdef DEBUG_PK + RSA_print_fp(stderr, ret->rsa, 8); +#endif + } else { + if (ret->dsa != NULL) + DSA_free(ret->dsa); + ret->dsa = k->dsa; + k->dsa = NULL; + success = 1; +#ifdef DEBUG_PK + DSA_print_fp(stderr, ret->dsa, 8); +#endif + } +/*XXXX*/ + key_free(k); + if (success != 1) + break; + /* advance cp: skip whitespace and data */ + while (*cp == ' ' || *cp == '\t') + cp++; + while (*cp != '\0' && *cp != ' ' && *cp != '\t') + cp++; + *cpp = cp; + break; + default: + fatal("key_read: bad key type: %d", ret->type); + break; + } + return success; +} +int +key_write(Key *key, FILE *f) +{ + int n, success = 0; + u_int len, bits = 0; + u_char *blob, *uu; + + if (key->type == KEY_RSA1 && key->rsa != NULL) { + /* size of modulus 'n' */ + bits = BN_num_bits(key->rsa->n); + fprintf(f, "%u", bits); + if (write_bignum(f, key->rsa->e) && + write_bignum(f, key->rsa->n)) { + success = 1; + } else { + error("key_write: failed for RSA key"); + } + } else if ((key->type == KEY_DSA && key->dsa != NULL) || + (key->type == KEY_RSA && key->rsa != NULL)) { + key_to_blob(key, &blob, &len); + uu = xmalloc(2*len); + n = uuencode(blob, len, uu, 2*len); + if (n > 0) { + fprintf(f, "%s %s", key_ssh_name(key), uu); + success = 1; + } + xfree(blob); + xfree(uu); + } + return success; +} +char * +key_type(Key *k) +{ + switch (k->type) { + case KEY_RSA1: + return "RSA1"; + break; + case KEY_RSA: + return "RSA"; + break; + case KEY_DSA: + return "DSA"; + break; + } + return "unknown"; +} +char * +key_ssh_name(Key *k) +{ + switch (k->type) { + case KEY_RSA: + return "ssh-rsa"; + break; + case KEY_DSA: + return "ssh-dss"; + break; + } + return "ssh-unknown"; +} +u_int +key_size(Key *k) +{ + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + return BN_num_bits(k->rsa->n); + break; + case KEY_DSA: + return BN_num_bits(k->dsa->p); + break; + } + return 0; +} + +static RSA * +rsa_generate_private_key(u_int bits) +{ + RSA *private; + private = RSA_generate_key(bits, 35, NULL, NULL); + if (private == NULL) + fatal("rsa_generate_private_key: key generation failed."); + return private; +} + +static DSA* +dsa_generate_private_key(u_int bits) +{ + DSA *private = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL); + if (private == NULL) + fatal("dsa_generate_private_key: DSA_generate_parameters failed"); + if (!DSA_generate_key(private)) + fatal("dsa_generate_private_key: DSA_generate_key failed."); + if (private == NULL) + fatal("dsa_generate_private_key: NULL."); + return private; +} + +Key * +key_generate(int type, u_int bits) +{ + Key *k = key_new(KEY_UNSPEC); + switch (type) { + case KEY_DSA: + k->dsa = dsa_generate_private_key(bits); + break; + case KEY_RSA: + case KEY_RSA1: + k->rsa = rsa_generate_private_key(bits); + break; + default: + fatal("key_generate: unknown type %d", type); + } + k->type = type; + return k; +} + +Key * +key_from_private(Key *k) +{ + Key *n = NULL; + switch (k->type) { + case KEY_DSA: + n = key_new(k->type); + BN_copy(n->dsa->p, k->dsa->p); + BN_copy(n->dsa->q, k->dsa->q); + BN_copy(n->dsa->g, k->dsa->g); + BN_copy(n->dsa->pub_key, k->dsa->pub_key); + break; + case KEY_RSA: + case KEY_RSA1: + n = key_new(k->type); + BN_copy(n->rsa->n, k->rsa->n); + BN_copy(n->rsa->e, k->rsa->e); + break; + default: + fatal("key_from_private: unknown type %d", k->type); + break; + } + return n; +} + +int +key_type_from_name(char *name) +{ + if (strcmp(name, "rsa1") == 0) { + return KEY_RSA1; + } else if (strcmp(name, "rsa") == 0) { + return KEY_RSA; + } else if (strcmp(name, "dsa") == 0) { + return KEY_DSA; + } else if (strcmp(name, "ssh-rsa") == 0) { + return KEY_RSA; + } else if (strcmp(name, "ssh-dss") == 0) { + return KEY_DSA; + } + debug2("key_type_from_name: unknown key type '%s'", name); + return KEY_UNSPEC; +} + +int +key_names_valid2(const char *names) +{ + char *s, *cp, *p; + + if (names == NULL || strcmp(names, "") == 0) + return 0; + s = cp = xstrdup(names); + for ((p = strsep(&cp, ",")); p && *p != '\0'; + (p = strsep(&cp, ","))) { + switch (key_type_from_name(p)) { + case KEY_RSA1: + case KEY_UNSPEC: + xfree(s); + return 0; + } + } + debug3("key names ok: [%s]", names); + xfree(s); + return 1; +} + +Key * +key_from_blob(u_char *blob, int blen) +{ + Buffer b; + char *ktype; + int rlen, type; + Key *key = NULL; + +#ifdef DEBUG_PK + dump_base64(stderr, blob, blen); +#endif + buffer_init(&b); + buffer_append(&b, blob, blen); + ktype = buffer_get_string(&b, NULL); + type = key_type_from_name(ktype); + + switch (type) { + case KEY_RSA: + key = key_new(type); + buffer_get_bignum2(&b, key->rsa->e); + buffer_get_bignum2(&b, key->rsa->n); +#ifdef DEBUG_PK + RSA_print_fp(stderr, key->rsa, 8); +#endif + break; + case KEY_DSA: + key = key_new(type); + buffer_get_bignum2(&b, key->dsa->p); + buffer_get_bignum2(&b, key->dsa->q); + buffer_get_bignum2(&b, key->dsa->g); + buffer_get_bignum2(&b, key->dsa->pub_key); +#ifdef DEBUG_PK + DSA_print_fp(stderr, key->dsa, 8); +#endif + break; + case KEY_UNSPEC: + key = key_new(type); + break; + default: + error("key_from_blob: cannot handle type %s", ktype); + break; + } + rlen = buffer_len(&b); + if (key != NULL && rlen != 0) + error("key_from_blob: remaining bytes in key blob %d", rlen); + xfree(ktype); + buffer_free(&b); + return key; +} + +int +key_to_blob(Key *key, u_char **blobp, u_int *lenp) +{ + Buffer b; + int len; + u_char *buf; + + if (key == NULL) { + error("key_to_blob: key == NULL"); + return 0; + } + buffer_init(&b); + switch (key->type) { + case KEY_DSA: + buffer_put_cstring(&b, key_ssh_name(key)); + buffer_put_bignum2(&b, key->dsa->p); + buffer_put_bignum2(&b, key->dsa->q); + buffer_put_bignum2(&b, key->dsa->g); + buffer_put_bignum2(&b, key->dsa->pub_key); + break; + case KEY_RSA: + buffer_put_cstring(&b, key_ssh_name(key)); + buffer_put_bignum2(&b, key->rsa->e); + buffer_put_bignum2(&b, key->rsa->n); + break; + default: + error("key_to_blob: unsupported key type %d", key->type); + buffer_free(&b); + return 0; + } + len = buffer_len(&b); + buf = xmalloc(len); + memcpy(buf, buffer_ptr(&b), len); + memset(buffer_ptr(&b), 0, len); + buffer_free(&b); + if (lenp != NULL) + *lenp = len; + if (blobp != NULL) + *blobp = buf; + return len; +} + +int +key_sign( + Key *key, + u_char **sigp, u_int *lenp, + u_char *data, u_int datalen) +{ + switch (key->type) { + case KEY_DSA: + return ssh_dss_sign(key, sigp, lenp, data, datalen); + break; + case KEY_RSA: + return ssh_rsa_sign(key, sigp, lenp, data, datalen); + break; + default: + error("key_sign: illegal key type %d", key->type); + return -1; + break; + } +} + +int +key_verify( + Key *key, + u_char *signature, u_int signaturelen, + u_char *data, u_int datalen) +{ + if (signaturelen == 0) + return -1; + + switch (key->type) { + case KEY_DSA: + return ssh_dss_verify(key, signature, signaturelen, data, datalen); + break; + case KEY_RSA: + return ssh_rsa_verify(key, signature, signaturelen, data, datalen); + break; + default: + error("key_verify: illegal key type %d", key->type); + return -1; + break; + } +} + +/* Converts a private to a public key */ + +Key * +key_demote(Key *k) +{ + Key *pk; + + pk = xmalloc(sizeof(*pk)); + pk->type = k->type; + pk->flags = k->flags; + pk->dsa = NULL; + pk->rsa = NULL; + + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if ((pk->rsa = RSA_new()) == NULL) + fatal("key_demote: RSA_new failed"); + if ((pk->rsa->e = BN_dup(k->rsa->e)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL) + fatal("key_demote: BN_dup failed"); + break; + case KEY_DSA: + if ((pk->dsa = DSA_new()) == NULL) + fatal("key_demote: DSA_new failed"); + if ((pk->dsa->p = BN_dup(k->dsa->p)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->q = BN_dup(k->dsa->q)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->g = BN_dup(k->dsa->g)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) + fatal("key_demote: BN_dup failed"); + break; + default: + fatal("key_free: bad key type %d", k->type); + break; + } + + return (pk); +} +/* + * key_verify returns 1 for a correct signature, 0 for an incorrect signature + * and -1 on error. + */ diff -urP --exclude-from=../exclude.list ssh/key.h ssh+x509c/key.h --- ssh/key.h Mon Mar 18 19:23:31 2002 +++ ssh+x509c/key.h Mon Jun 24 21:04:00 2002 @@ -28,12 +28,15 @@ #include #include +#include typedef struct Key Key; enum types { KEY_RSA1, KEY_RSA, KEY_DSA, + KEY_X509_RSA, + KEY_X509_DSA, KEY_UNSPEC }; enum fp_type { @@ -53,6 +56,7 @@ int flags; RSA *rsa; DSA *dsa; + X509 *x509; }; Key *key_new(int); diff -urP --exclude-from=../exclude.list ssh/lib/Makefile ssh+x509c/lib/Makefile --- ssh/lib/Makefile Tue Jun 11 18:23:29 2002 +++ ssh+x509c/lib/Makefile Mon Jun 24 20:36:46 2002 @@ -8,7 +8,7 @@ hostfile.c log.c match.c mpaux.c nchan.c packet.c readpass.c \ rsa.c tildexpand.c ttymodes.c xmalloc.c atomicio.c \ key.c dispatch.c kex.c mac.c uuencode.c misc.c \ - rijndael.c ssh-dss.c ssh-rsa.c dh.c kexdh.c kexgex.c \ + rijndael.c ssh-dss.c ssh-rsa.c ssh-x509.c dh.c kexdh.c kexgex.c \ scard.c monitor_wrap.c monitor_fdpass.c msg.c DEBUGLIBS= no diff -urP --exclude-from=../exclude.list ssh/monitor.c ssh+x509c/monitor.c --- ssh/monitor.c Fri Jun 21 08:50:51 2002 +++ ssh+x509c/monitor.c Mon Jun 24 20:46:50 2002 @@ -58,6 +58,7 @@ #include "compat.h" #include "ssh2.h" #include "mpaux.h" +#include "ssh-x509.h" /* Imports */ extern ServerOptions options; @@ -727,7 +728,9 @@ chost = buffer_get_string(m, NULL); blob = buffer_get_string(m, &bloblen); - key = key_from_blob(blob, bloblen); + key = x509key_from_blob(blob, bloblen); + if (key == NULL) + key = key_from_blob(blob, bloblen); if ((compat20 && type == MM_RSAHOSTKEY) || (!compat20 && type != MM_RSAHOSTKEY)) @@ -916,7 +919,9 @@ !monitor_allowed_key(blob, bloblen)) fatal("%s: bad key, not previously allowed", __func__); - key = key_from_blob(blob, bloblen); + key = x509key_from_blob(blob, bloblen); + if (key == NULL) + key = key_from_blob(blob, bloblen); if (key == NULL) fatal("%s: bad public key blob", __func__); diff -urP --exclude-from=../exclude.list ssh/pathnames.h ssh+x509c/pathnames.h --- ssh/pathnames.h Thu May 23 22:24:30 2002 +++ ssh+x509c/pathnames.h Mon Jun 24 20:40:24 2002 @@ -14,6 +14,7 @@ #define ETCDIR "/etc" #define SSHDIR ETCDIR "/ssh" +#define SSHCADIR SSHDIR "/ca" #define _PATH_SSH_PIDDIR "/var/run" /* @@ -36,6 +37,12 @@ #define _PATH_DH_MODULI ETCDIR "/moduli" /* Backwards compatibility */ #define _PATH_DH_PRIMES ETCDIR "/primes" + +/* x509 store */ +#define _PATH_CA_CERTIFICATE_FILE SSHCADIR "/ca-bundle.crt" +#define _PATH_CA_CERTIFICATE_PATH SSHCADIR "/crt" +#define _PATH_CA_REVOCATION_FILE SSHCADIR "/ca-bundle.crl" +#define _PATH_CA_REVOCATION_PATH SSHCADIR "/crl" #define _PATH_SSH_PROGRAM "/usr/bin/ssh" diff -urP --exclude-from=../exclude.list ssh/servconf.c ssh+x509c/servconf.c --- ssh/servconf.c Fri Jun 21 02:05:55 2002 +++ ssh+x509c/servconf.c Mon Jun 24 21:02:12 2002 @@ -108,6 +108,11 @@ options->client_alive_count_max = -1; options->authorized_keys_file = NULL; options->authorized_keys_file2 = NULL; + options->num_allowedcertpurposes = 0; + options->ca_certificate_file = NULL; + options->ca_certificate_path = NULL; + options->ca_revocation_file = NULL; + options->ca_revocation_path = NULL; /* Needs to be accessable in many places */ use_privsep = -1; @@ -233,6 +238,15 @@ } if (options->authorized_keys_file == NULL) options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS; + /* options->num_allowedcertpurposes is zero by default */ + if (options->ca_certificate_file == NULL) + options->ca_certificate_file = _PATH_CA_CERTIFICATE_FILE; + if (options->ca_certificate_path == NULL) + options->ca_certificate_path = _PATH_CA_CERTIFICATE_PATH; + if (options->ca_revocation_file == NULL) + options->ca_revocation_file = _PATH_CA_REVOCATION_FILE; + if (options->ca_revocation_path == NULL) + options->ca_revocation_path = _PATH_CA_REVOCATION_PATH; /* Turn privilege separation on by default */ if (use_privsep == -1) @@ -267,6 +281,9 @@ sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, sUsePrivilegeSeparation, + sAllowedCertPurposes, + sCACertificateFile, sCACertificatePath, + sCARevocationFile, sCARevocationPath, sDeprecated } ServerOpCodes; @@ -341,6 +358,11 @@ { "authorizedkeysfile", sAuthorizedKeysFile }, { "authorizedkeysfile2", sAuthorizedKeysFile2 }, { "useprivilegeseparation", sUsePrivilegeSeparation}, + { "allowedcertpurposes", sAllowedCertPurposes }, + { "cacertificatefile", sCACertificateFile }, + { "cacertificatepath", sCACertificatePath }, + { "carevocationfile", sCARevocationFile }, + { "carevocationpath", sCARevocationPath }, { NULL, sBadOption } }; @@ -857,6 +879,33 @@ case sClientAliveCountMax: intptr = &options->client_alive_count_max; goto parse_int; + +#if 0 + case sAllowedCertPurposes: + options->num_allowedcertpurposes = XXXX + options->allowedcertpurposes = XXXX + break; +#endif + + case sCACertificateFile: + case sCACertificatePath: + case sCARevocationFile: + case sCARevocationPath: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing argument.", filename, linenum); + switch (opcode) { + case sCACertificateFile: + options->ca_certificate_file = xstrdup(arg); break; + case sCACertificatePath: + options->ca_certificate_path = xstrdup(arg); break; + case sCARevocationFile: + options->ca_revocation_file = xstrdup(arg); break; + case sCARevocationPath: + options->ca_revocation_path = xstrdup(arg); break; + default: + } + break; case sDeprecated: log("%s line %d: Deprecated option %s", diff -urP --exclude-from=../exclude.list ssh/servconf.h ssh+x509c/servconf.h --- ssh/servconf.h Fri Jun 21 02:05:55 2002 +++ ssh+x509c/servconf.h Mon Jun 24 20:57:43 2002 @@ -130,6 +130,14 @@ char *authorized_keys_file; /* File containing public keys */ char *authorized_keys_file2; + + /* ssh PKI(X509) store */ + int num_allowedcertpurposes; + char *allowedcertpurposes[10]; /* XXXX*/ + char *ca_certificate_file; + char *ca_certificate_path; + char *ca_revocation_file; + char *ca_revocation_path; } ServerOptions; void initialize_server_options(ServerOptions *); diff -urP --exclude-from=../exclude.list ssh/ssh-x509.c ssh+x509c/ssh-x509.c --- ssh/ssh-x509.c Thu Jan 1 02:00:00 1970 +++ ssh+x509c/ssh-x509.c Mon Jun 17 21:37:05 2002 @@ -0,0 +1,592 @@ +/* + * Copyright (c) 2002 Roumen Petrov. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "ssh-x509.h" +#include "includes.h" +#include "log.h" +#include +#include "xmalloc.h" +#include "uuencode.h" +#include +#include "bufaux.h" +#include "x509store.h" + + +#define USE_X509STORE +#ifdef USE_X509STORE +int (*pssh_x509_store_check)(X509 *_cert) = NULL; +#endif + + +static char* +x509key_get_subject(int _keytype, char* _cp) { + static char *keywords[] = { + "subject", + "distinguished name", + "distinguished_name", + "dn", + NULL + }; + char **q, *p; + size_t len; + + if (_keytype != KEY_X509_RSA && + _keytype != KEY_X509_DSA) { + debug3("x509key_get_subject: %d is not x509 key ", _keytype); + return 0; + } + for (q=keywords; *q; q++) { + len = strlen(*q); + if (strncasecmp(_cp, *q, len) == 0) { + for (p = _cp + len; *p && isspace(*p); p++) + {} + if (!*p) { + error("x509key_get_subject: no data"); + return NULL; + } + if (*p == ':' || *p == '=') + p++; + for (; *p && isspace(*p); p++) + {} + if (!*p) { + error("x509key_get_subject: no data"); + return NULL; + } + if (*p == '/') + p++; + return p; + } + } + return NULL; +} + + +static int +x509key_str2X509NAME(char* _str, X509_NAME *_name) { + int ret = 1; + char *p, *q, *token; + char ch; + + p = _str; + while (*p) { + int nid; + for (; *p && isspace(*p); p++) + {} + if (!*p) break; + token = strchr(p, ','); + if (token == NULL) token = strchr(p, '/'); + if (token) { + ch = *token; + *token = 0; + } else { + ch = 0; + token = p + strlen(p); + } + q = strchr(p, '='); + if (!q) { + error("x509key_str2X509NAME: cannot parse %.200s ...", p); + ret = 0; + break; + } + *q = 0; + nid = OBJ_txt2nid(p); + *q = '='; + p = q + 1; + if(!*p) { + error("x509key_str2X509NAME: no data"); + ret = 0; + } else { /* add */ + + for(q = token - 1; (q >= p) && isspace(*q); q--) + {/*skip unexpected \n,etc. from end*/} + ret = X509_NAME_add_entry_by_NID(_name, nid, V_ASN1_PRINTABLESTRING, p, q-p+1, -1, 0); + if(ret <= 0) { + int ecode = ERR_get_error(); + error("x509key_from_subject: x509key_str2X509NAME fail %.200s", ERR_error_string(ecode, NULL)); + } + } + *token = ch; + if(ret <= 0) { + break; + } + p = token; + if(*p) p++; + } + debug3("x509key_str2X509NAME: return %d", ret); + return ret; +} + + +Key* +x509key_from_subject(int _keytype, char* _cp) { + int ret = 1; + Key* key = NULL; + X509_NAME *subj; + char *subject; + + debug3("x509key_from_subject(%d, [%.200s]) called ", _keytype, _cp); + subject = x509key_get_subject(_keytype, _cp); + if(subject == NULL) + return NULL; + + debug3("x509key_from_subject(...) subject=[%.200s]", subject); + key = key_new(_keytype); + if (key == NULL) { + error("x509key_from_subject(): out of memory"); + return NULL; + } + + if (ret > 0) { + subj = X509_get_subject_name(key->x509); + if (subj == NULL) { + error("x509key_from_subject(): new x509 key without subject"); + ret = 0; + } + } + + if (ret > 0) { + ret = x509key_str2X509NAME(subject, subj); + } + + if (ret <= 0) { + if (key) { + key_free(key); + key = NULL; + } + } + return key; +} + + +static Key* +x509_to_key(X509 *x509) { + Key *key = NULL; + EVP_PKEY *env_pkey; + + env_pkey = X509_get_pubkey(x509); + + if (env_pkey == NULL) { + int ecode = ERR_get_error(); + error("x509_to_key: X509_get_pubkey fail %.200s", ERR_error_string(ecode, NULL)); + return key; + } + else { + debug3("x509_to_key: X509_get_pubkey done!"); + } + + switch(env_pkey->type) { + case EVP_PKEY_RSA: + key = key_new(KEY_UNSPEC); + key->x509 = x509; + key->rsa = EVP_PKEY_get1_RSA(env_pkey); + key->type = KEY_X509_RSA; +#ifdef DEBUG_PK + RSA_print_fp(stderr, key->rsa, 8); +#endif + break; + + case EVP_PKEY_DSA: + key = key_new(KEY_UNSPEC); + key->x509 = x509; + key->dsa = EVP_PKEY_get1_DSA(env_pkey); + key->type = KEY_X509_DSA; +#ifdef DEBUG_PK + DSA_print_fp(stderr, key->dsa, 8); +#endif + break; + + default: + debug3("x509key_from_blob:unspec key" ); + } + + return key; +} + + +Key* +x509key_from_blob( + u_char *blob, + int blen +) { + Key* key = NULL; + BIO *mbio; + + /* convert blob data to BIO certificate data */ + mbio=BIO_new(BIO_s_mem()); + if (mbio == NULL) return NULL; + BIO_write(mbio,blob,blen); + BIO_flush(mbio); + + debug3("x509key_from_blob:We have %d bytes available in BIO",BIO_pending(mbio)); + + { /* read X509 certificate from BIO data */ + X509* x509 = NULL; + x509 = d2i_X509_bio(mbio,NULL); + if (x509 == NULL) { + int ecode = ERR_get_error(); + error("x509key_from_blob: read X509 from BIO fail %.200s", ERR_error_string(ecode, NULL)); + } + else { + key = x509_to_key(x509); + if (key == NULL) + X509_free(x509); + } + } + + /* This call will walk the chain freeing all the BIOs */ + BIO_free_all(mbio); + return key; +} + + +static int +x509key_check(char* method, Key *key) { + if (key == NULL) + { error("%.50s: no key", method); return 0; } + + if (key->type != KEY_X509_RSA && + key->type != KEY_X509_DSA ) + { error("%.50s: cannot handle key type %d", method, key->type); return 0; } + + if (key->x509 == NULL) + { error("%.50s: no X509 key", method); return 0; } + + return 1; +} + + +int +x509key_to_blob( + Key *key, + Buffer *b +) { + int len; + void* str; + unsigned char *p; + + if (!x509key_check("x509key_to_blob", key)) + return 0; + + len = i2d_X509(key->x509, NULL); + str = xmalloc(len); + if (str == NULL) + { error("x509key_to_blob: out of memory"); return 0; } + + p = str; + i2d_X509(key->x509, &p); + buffer_append(b, str, len); + xfree(str); + return 1; +} + + +int +x509key_write( + Key *key, + FILE *f +) { + int ret = 0; + Buffer b; + int n; + + if (!x509key_check("x509key_write", key)) + return ret; + + buffer_init(&b); + ret = x509key_to_blob(key,&b); + if (ret) { + /* write ssh key name */ + char * ktype = key_ssh_name(key); + n = strlen(ktype); + ret = ( fwrite(ktype, 1, n, f) == n ) && + ( fwrite(" " , 1, 1, f) == 1 ); + } + if (ret) { + u_char uu[1<<12]; //4096 + + n = uuencode(buffer_ptr(&b), buffer_len(&b), uu, sizeof(uu)); + ret = n > 0; + if (ret) { + ret = (fwrite(uu, 1, n, f) == n); + } + } + buffer_free(&b); + return ret; +} + + +Key* +x509key_load_cert( + Key *key, + FILE *fp +) { + if (!key) return NULL; + + if ( (key->type == KEY_RSA) || + (key->type == KEY_DSA) ) { + key->x509 = PEM_read_X509(fp, NULL, NULL, NULL); + if (key->x509 == NULL) { + int ecode = ERR_get_error(); + debug3("x509key_load_cert: PEM_read_X509 fail %.200s", ERR_error_string(ecode, NULL)); + } + else { + key->type = (key->type == KEY_RSA) ? KEY_X509_RSA : KEY_X509_DSA; + debug("read X509 certificate done: type %.40s", + key ? key_type(key) : ""); + } + } + return key; +} + + +static int +x509key_save_cert( + FILE *fp, + X509 *x509 +) { + int ret = 0; + BIO *out=NULL; + char buf[512]; + unsigned long nmflag = 0; + + out=BIO_new_fp(fp, BIO_NOCLOSE); +#ifdef VMS + { + BIO *tmpbio = BIO_new(BIO_f_linebuffer()); + out = BIO_push(tmpbio, out); + } +#endif + + BIO_puts(out, "issuer= "); + //X509_NAME_print_ex(out, X509_get_issuer_name(x509) , 0, nmflag); + X509_NAME_oneline(X509_get_issuer_name(x509), buf, sizeof(buf)); + BIO_puts(out, buf); + BIO_puts(out, "\n"); + + BIO_puts(out, "subject= "); + //X509_NAME_print_ex(out, X509_get_subject_name(x509), 0, nmflag); + X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf)); + BIO_puts(out, buf); + BIO_puts(out, "\n"); + { + unsigned char *alstr; + alstr = X509_alias_get0(x509, NULL); + if (!alstr) alstr = ""; + BIO_puts(out,alstr); + BIO_puts(out, "\n"); + } + ret = PEM_write_bio_X509(out, x509); + //ret = 0; + if (!ret) { + int ecode = ERR_get_error(); + error("x509key_save_cert: PEM_write_bio_X509 fail %.200s", ERR_error_string(ecode, NULL)); + } + + BIO_free_all(out); + return ret; +} + + +int +x509key_save_pem( + FILE *fp, + Key *key, + const EVP_CIPHER *cipher, + u_char *passphrase, + int len +) { + if (!x509key_check("x509key_save_pem", key)) + return 0; + + switch (key->type) { + case KEY_X509_DSA: + if(PEM_write_DSAPrivateKey(fp, key->dsa, cipher, passphrase, len, NULL, NULL)) + return x509key_save_cert(fp, key->x509); + break; + case KEY_X509_RSA: + if(PEM_write_RSAPrivateKey(fp, key->rsa, cipher, passphrase, len, NULL, NULL)) + return x509key_save_cert(fp, key->x509); + break; + } + return 0; +} + + +int +ssh_x509_sign( + Key * key, + u_char **psignature, u_int *psignaturelen, + u_char *data, u_int datalen +) { + int ret = -1; + u_char sigret[256]; + u_int siglen; + + if (!x509key_check("ssh_x509_sign", key)) + return ret; + if((key->rsa == NULL) && (key->dsa == NULL)) { + error("ssh_x509_sign: missing private key"); + return ret; + } + + debug3("ssh_x509_sign: key_type=%.20s, key_ssh_name=%.40s", key_type(key), key_ssh_name(key)); + ret = 1; + { + EVP_PKEY* privkey = NULL; + + privkey = EVP_PKEY_new(); + if (!privkey) { + error("ssh_x509_sign: out of memory"); + ret = -1; + } + else { + ret = (key->rsa) + ? EVP_PKEY_set1_RSA(privkey, key->rsa) + : EVP_PKEY_set1_DSA(privkey, key->dsa); + + if (ret <= 0) { + int ecode = ERR_get_error(); + error("ssh_x509_sign: EVP_PKEY_set1_XXX: failed %.200s", ERR_error_string(ecode, NULL)); + } + } + + if (ret > 0) { + EVP_MD_CTX ctx; + const EVP_MD *evp_md = (key->rsa) ? EVP_md5() : EVP_dss1(); + debug3("ssh_x509_sign: evp_md { %d, %d, %d, ... }", evp_md->type, evp_md->pkey_type, evp_md->md_size); + + EVP_SignInit(&ctx,evp_md); + EVP_SignUpdate(&ctx,data,datalen); + + if (ret > 0) { + ret = EVP_SignFinal(&ctx,sigret,&siglen,privkey); + if (ret <= 0) { + int ecode = ERR_get_error(); + error("ssh_x509_sign: digest failed: %.200s", ERR_error_string(ecode, NULL)); + } + } + } + EVP_PKEY_free(privkey); + } + if (ret > 0) { + Buffer b; + + buffer_init(&b); + buffer_put_cstring(&b, key_ssh_name(key)); + buffer_put_string(&b, sigret, siglen); + + { + u_int len = buffer_len(&b); + if (psignaturelen != NULL) + *psignaturelen = len; + + if (psignature != NULL) { + *psignature = xmalloc(len); + memcpy(*psignature, buffer_ptr(&b), len); + } + } + buffer_free(&b); + } + debug3("ssh_x509_sign() return %d", ret); + return ret; +} + + +int ssh_x509_verify( + Key *key, + u_char *signature, u_int signaturelen, + u_char *data, u_int datalen) +{ + int ret = -1; + u_char *sigblob = NULL; + uint len = 0; + + + if (!x509key_check("ssh_x509_verify", key)) + return ret; + + { /* get signature data only */ + Buffer b; + buffer_init(&b); + buffer_append(&b, signature, signaturelen); + + { /* check signature key type */ + char *ktype = buffer_get_string(&b, NULL); + debug3("ssh_x509_verify signature key type = %.40s", ktype ); + ret = strcmp("x509v3-sign-rsa", ktype) == 0 || + strcmp("x509v3-sign-dss", ktype) == 0; + if (!ret) { + error("ssh_x509_verify: cannot handle signature key type %.40s", ktype); + } + xfree(ktype); + } + + if (ret > 0) { + sigblob = buffer_get_string(&b, &len); + } + + if (ret > 0) { + int rlen = buffer_len(&b); + if (rlen != 0) { + error("ssh_x509_verify: remaining bytes in signature %d", rlen); + ret = -1; + } + } + buffer_free(&b); + } + + if (ret > 0 ) { + EVP_PKEY* pubkey; + + pubkey = X509_get_pubkey(key->x509); + if (!pubkey) { + error("ssh_x509_verify: no 'X509 Public Key'"); + ret = -1; + } + + if (ret > 0) { + EVP_MD_CTX ctx; + const EVP_MD *evp_md = (key->rsa) ? EVP_md5() : EVP_dss1(); + debug3("ssh_x509_verify: evp_md { %d, %d, %d, ... }", evp_md->type, evp_md->pkey_type, evp_md->md_size); + + EVP_VerifyInit(&ctx,evp_md); + EVP_VerifyUpdate(&ctx,data,datalen); + ret = EVP_VerifyFinal(&ctx,sigblob,len,pubkey); + if (ret <= 0) { + int ecode = ERR_get_error(); + error("ssh_x509_verify: verify failed: %.200s", ERR_error_string(ecode, NULL)); + } + } + } +#ifdef USE_X509STORE + if (ret > 0 && pssh_x509_store_check != NULL) { + ret = (*pssh_x509_store_check)(key->x509); + } +#endif + if (sigblob) { + memset(sigblob, 's', len); + xfree(sigblob); + } + debug3("ssh_x509_verify() return %d", ret); + return ret; +} diff -urP --exclude-from=../exclude.list ssh/ssh-x509.h ssh+x509c/ssh-x509.h --- ssh/ssh-x509.h Thu Jan 1 02:00:00 1970 +++ ssh+x509c/ssh-x509.h Mon Jun 17 15:44:42 2002 @@ -0,0 +1,50 @@ +#ifndef SSH_X509_H +#define SSH_X509_H +/* + * Copyright (c) 2002 Roumen Petrov. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "key.h" +#include "buffer.h" + + /* + * This method return a key(x509) only with "Distinguished Name" ! + */ +Key* x509key_from_subject(int _keytype, char* _cp); + + +Key* x509key_from_blob(u_char *blob, int blen); +int x509key_to_blob(Key *key, Buffer *b); +int x509key_write(Key *key, FILE *f); + +Key* x509key_load_cert(Key *key, FILE *fp); + +int x509key_save_pem(FILE *fp, Key *key, const EVP_CIPHER *cipher, u_char *passphrase, int len); + + +int ssh_x509_sign(Key *, u_char **, u_int *, u_char *, u_int); +int ssh_x509_verify(Key *key, u_char *signature, u_int signaturelen, u_char *data, u_int datalen); + + +#endif /* SSH_X509_H */ diff -urP --exclude-from=../exclude.list ssh/sshconnect2.c ssh+x509c/sshconnect2.c --- ssh/sshconnect2.c Wed Jun 19 03:27:55 2002 +++ ssh+x509c/sshconnect2.c Mon Jun 24 20:56:45 2002 @@ -47,6 +47,7 @@ #include "canohost.h" #include "msg.h" #include "pathnames.h" +#include "ssh-x509.h" /* import */ extern char *client_version_string; @@ -388,7 +389,11 @@ debug("unknown pkalg %s", pkalg); break; } - if ((key = key_from_blob(pkblob, blen)) == NULL) { + if ( (pktype == KEY_X509_RSA) || (pktype == KEY_X509_RSA) ) + key = x509key_from_blob(pkblob, blen); + else + key = key_from_blob(pkblob, blen); + if (key == NULL) { debug("no key from blob. pkalg %s", pkalg); break; } diff -urP --exclude-from=../exclude.list ssh/sshd/Makefile ssh+x509c/sshd/Makefile --- ssh/sshd/Makefile Thu Jun 20 22:56:07 2002 +++ ssh+x509c/sshd/Makefile Mon Jun 24 20:37:35 2002 @@ -13,7 +13,7 @@ sshpty.c sshlogin.c servconf.c serverloop.c uidswap.c \ auth.c auth1.c auth2.c auth-options.c session.c \ auth-chall.c auth2-chall.c groupaccess.c \ - auth-skey.c auth-bsdauth.c monitor_mm.c monitor.c \ + auth-skey.c auth-bsdauth.c monitor_mm.c monitor.c x509store.c \ auth2-none.c auth2-passwd.c auth2-pubkey.c \ auth2-hostbased.c auth2-kbdint.c diff -urP --exclude-from=../exclude.list ssh/sshd.c ssh+x509c/sshd.c --- ssh/sshd.c Fri Jun 21 02:05:56 2002 +++ ssh+x509c/sshd.c Mon Jun 24 20:41:57 2002 @@ -80,6 +80,7 @@ #include "monitor.h" #include "monitor_wrap.h" #include "monitor_fdpass.h" +#include "x509store.h" #ifdef LIBWRAP #include @@ -782,6 +783,7 @@ /* Initialize configuration options to their default values. */ initialize_server_options(&options); + pssh_x509_store_check = ssh_x509_store_check; /* Parse command-line arguments. */ while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:o:dDeiqtQ46")) != -1) { diff -urP --exclude-from=../exclude.list ssh/sshd_config ssh+x509c/sshd_config --- ssh/sshd_config Fri Jun 21 02:37:12 2002 +++ ssh+x509c/sshd_config Mon Jun 24 20:42:59 2002 @@ -19,6 +19,12 @@ #HostKey /etc/ssh/ssh_host_rsa_key #HostKey /etc/ssh/ssh_host_dsa_key +#AllowedCertPurposes XXXX +#CACertificateFile /etc/ssh/ca/ca-bundle.crt +#CACertificatePath /etc/ssh/ca/crt +#CARevocationFile /etc/ssh/ca/ca-bundle.crl +#CARevocationPath /etc/ssh/ca/crl + # Lifetime and size of ephemeral version 1 server key #KeyRegenerationInterval 3600 #ServerKeyBits 768 diff -urP --exclude-from=../exclude.list ssh/tests/CA/1-cre_cadb.sh ssh+x509c/tests/CA/1-cre_cadb.sh --- ssh/tests/CA/1-cre_cadb.sh Thu Jan 1 02:00:00 1970 +++ ssh+x509c/tests/CA/1-cre_cadb.sh Mon Jun 17 16:06:16 2002 @@ -0,0 +1,207 @@ +#!/bin/sh +# Copyright (c) 2002 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# DESCRIPTION: Create a new certificate authority config and database. +# + +cd `dirname "$0"` +. ./functions +. ./config + + +# === +echo_CA_common_options () { +cat < "$1" +[ ca ] +default_ca = CA_OpenSSH_rsa_md5 + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ req ] +default_bits = 1024 +distinguished_name = req_distinguished_name +attributes = req_attributes +#prompt = no + +# The extensions to add to a certificate request: +#???req_extensions = usr_cert + + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = $SSH_DN_C +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = $SSH_DN_ST + +localityName = Locality Name (eg, city) + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = $SSH_DN_O + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = $SSH_DN_OU + +commonName = Common Name (eg, YOUR name) +commonName_min = 2 +commonName_max = 64 + +emailAddress = Email Address (optional) +emailAddress_max = 40 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +[ usr_cert ] +# These extensions are added when 'ca' signs a request. +basicConstraints=CA:FALSE +nsCertType = client, email + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Client Test Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always + +[ srv_cert ] +# These extensions are added when 'ca' signs a request. +basicConstraints = CA:FALSE +nsCertType = server + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Server Test Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always + +EOF + + +for DIGEST in ${RSA_DIGEST_LIST}; do +( cat << EOF + + +[ CA_OpenSSH_rsa_${DIGEST} ] +EOF + echo_CA_common_options + cat << EOF +# which md to use: +default_md = ${DIGEST} + +# The private key (!) +private_key = "${SSH_CAKEYDIR}/${RSA_BASENAME}.key" + +#The CA certificate (!) +certificate = "${SSH_CACERTDIR}/${RSA_BASENAME}_${DIGEST}.crt.pem" +EOF +) >> "$1" +done + +( cat << EOF + + +[ CA_OpenSSH_dsa ] +EOF + echo_CA_common_options + cat << EOF +# which md to use: +default_md = sha1 + +# The private key (!) +private_key = "${SSH_CAKEYDIR}/${DSA_BASENAME}.key" + +#The CA certificate (!) +certificate = "${SSH_CACERTDIR}/${DSA_BASENAME}.crt.pem" +EOF +) >> "$1" +} + + +# === +cre_db () { + var="${SSH_CAROOT}" + if test ! -d "$var"; then + mkdir -p "$var" || return $? + else + count=`getNextDirName "${var}"` || return $? + if test -d "${var}"; then + echo -n "saving old directoty as ${attn}${var}.${warn}${count}${norm} ... " + mv "${var}" "${var}.${count}"; show_status $? || return $? + fi + fi + mkdir -p "$var" && + mkdir "$var/crt" && + mkdir "$var/crl" && + cp /dev/null "$var/index.txt" && + mkdir "$var/newcerts" && + echo '01' > "$var/serial" +} + + +# === +cre_config "${TMPDIR}/${CACONFIG}" && +cre_db && +update_file "${TMPDIR}/${CACONFIG}" "${SSH_CACFGFILE}" + + +show_status $? "${extd}Creating a new ${warn}TEST${norm} ${attn}Certificate Authority Database${norm} ..." + diff -urP --exclude-from=../exclude.list ssh/tests/CA/2-cre_cakeys.sh ssh+x509c/tests/CA/2-cre_cakeys.sh --- ssh/tests/CA/2-cre_cakeys.sh Thu Jan 1 02:00:00 1970 +++ ssh+x509c/tests/CA/2-cre_cakeys.sh Mon Jun 17 23:51:10 2002 @@ -0,0 +1,241 @@ +#!/bin/sh +# Copyright (c) 2002 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# DESCRIPTION: Create "Test Certificate Authority" private keys and certificates. +# + +cd `dirname "$0"` +. ./functions +. ./config + + +# === +SSH_DN_OU="OpenSSH Test CA Root" +SSH_DN_CN_BASE="OpenSSH Test CA key" + + +echo_SSH_CA_DN () { +cat </dev/null + +$OPENSSL genrsa ${RSA_OPT} \ + -passout pass:${KEY_PASS} \ + -out "${TMPDIR}/${RSA_BASENAME}.key" 1024 \ + 2>/dev/null \ +; show_status $? "${extd}generating a new ${attn}rsa ${norm} private key for the ${warn}TEST${norm}${extd} ${attn}CA${norm} ..." \ +|| exit $? + + +for DIGEST in ${RSA_DIGEST_LIST}; do + +rm -f "${TMPDIR}/${RSA_BASENAME}_${DIGEST}.crt" 2>/dev/null + +echo_SSH_CA_DN "rsa_${DIGEST}" | +$OPENSSL req -new -x509 \ + -days $SSH_CACERTDAYS \ + -passin pass:${KEY_PASS} \ + -key "${TMPDIR}/${RSA_BASENAME}.key" \ + -${DIGEST} \ + -out "${TMPDIR}/${RSA_BASENAME}_${DIGEST}.crt" \ + 2> /dev/null \ +; show_status $? "${extd}generating the new ${warn}TEST${norm}${extd} ${attn}CA${norm}/(${DIGEST} with rsa) ..." \ +|| exit $? + +done +} + + +# === +gen_dsa () { +DSA_OPT="" +if [ -f /etc/random-seed ]; then + DSA_OPT="${DSA_OPT} -rand /etc/random-seed" +fi + +rm -f "${TMPDIR}/${DSA_BASENAME}.prm" 2>/dev/null +$OPENSSL dsaparam ${DSA_OPT} \ + -out "${TMPDIR}/${DSA_BASENAME}.prm" 1024\ + 2> /dev/null;\ +show_status $? "${extd}generating a new ${attn}DSA parameter file${norm} ..." \ +|| exit $? + +rm -f "${TMPDIR}/${DSA_BASENAME}.key" 2>/dev/null +DSA_OPT="${DSA_OPT} -des3" +$OPENSSL gendsa ${DSA_OPT} \ + -passout pass:${KEY_PASS} \ + -out "${TMPDIR}/${DSA_BASENAME}.key" \ + "${TMPDIR}/${DSA_BASENAME}.prm" \ + 2>/dev/null \ +; show_status $? "${extd}generating a new ${attn}dsa${norm} private key for the ${warn}TEST${norm}${extd} ${attn}CA${norm} ..." \ +|| exit $? + + +#request & ceritificate +rm -f "${TMPDIR}/${DSA_BASENAME}.crt" 2>/dev/null + +echo_SSH_CA_DN "dsa" | +$OPENSSL req -new -x509 \ + -days $SSH_CACERTDAYS \ + -passin pass:${KEY_PASS} \ + -key "${TMPDIR}/${DSA_BASENAME}.key" \ + -out "${TMPDIR}/${DSA_BASENAME}.crt" \ + 2> /dev/null \ +; show_status $? "${extd}generating the new ${warn}TEST${norm}${extd} ${attn}CA${norm}/(sha1 with dsa) ..." \ +|| exit $? + +} + + +# === +crt2bundle () { + val="$1" + test -z "${val}" && { echo ${warn}missing DN${norm} 1>&2; return 1; } + echo + echo ${val} + echo ${val} | sed -e 's/./=/g' + openssl x509 -inform PEM -in "${2}" -fingerprint -noout + echo PEM data: + openssl x509 -inform PEM -in "${2}" -trustout + echo Certificate Ingredients: + openssl x509 -inform PEM -in "${2}" -text -noout +} + + +# === +install () { + + for D in \ + "${SSH_CAROOT}" \ + "${SSH_CAKEYDIR}" \ + "${SSH_CACERTDIR}" \ + ;do + test ! -d "$D" && mkdir -p "${D}" + done + + update_file "${TMPDIR}/${DSA_BASENAME}.prm" "${SSH_CAROOT}/${DSA_BASENAME}.prm" \ +&& + chmod 700 "${SSH_CAKEYDIR}" \ +&& + update_file "${TMPDIR}/${RSA_BASENAME}.key" "${SSH_CAKEYDIR}/${RSA_BASENAME}.key" && + chmod 400 "${SSH_CAKEYDIR}/${RSA_BASENAME}.key" \ +&& + update_file "${TMPDIR}/${DSA_BASENAME}.key" "${SSH_CAKEYDIR}/${DSA_BASENAME}.key" && + chmod 400 "${SSH_CAKEYDIR}/${DSA_BASENAME}.key" \ +|| return 1 + + +for DIGEST in ${RSA_DIGEST_LIST}; do + update_file "${TMPDIR}/${RSA_BASENAME}_${DIGEST}.crt" "${SSH_CACERTDIR}/${RSA_BASENAME}_${DIGEST}.crt.pem" || return 1 +done + update_file "${TMPDIR}/${DSA_BASENAME}.crt" "${SSH_CACERTDIR}/${DSA_BASENAME}.crt.pem" || return 1 + + +echo -n > "${TMPDIR}/${CACERTFILE}" +for DIGEST in ${RSA_DIGEST_LIST}; do + crt2bundle "$SSH_DN_OU" "${SSH_CACERTDIR}/${RSA_BASENAME}_${DIGEST}.crt.pem" \ + >> "${TMPDIR}/${CACERTFILE}" \ + || return 1 +done + + crt2bundle "$SSH_DN_OU" "${SSH_CACERTDIR}/${DSA_BASENAME}.crt.pem" \ + >> "${TMPDIR}/${CACERTFILE}" \ + || return 1 + +update_file "${TMPDIR}/${CACERTFILE}" "${SSH_CAROOT}/${CACERTFILE}" +} + + +# === +rm_all_hash () { + local HASH=$1 + for F in $HASH.*; do + test -h $F && rm -f $F + done +} + + +get_next_hashname () { + name="$1" + let N=0 + while true; do + if [ ! -f "$name.$N" ]; then + break; + fi + let N=N+1 + done + echo $N; +} + + +che_hash_link () { + local HASH=`$OPENSSL x509 -in "$1" -noout -hash` + local N=`get_next_hashname $HASH` + ln -sf "$1" $HASH.$N +} + + +cre_hashs () { +#(!) openssl script "c_rehash" is missing in some installations :-( +# c_rehash "${SSH_CACERTDIR}" +( cd "${SSH_CACERTDIR}" + for F in [0-9a-f]*.[0-9]; do + # we must use test -L, but on ?-OSes ... :-( + if test -h $F; then + rm "$F" + fi + done + + for DIGEST in ${RSA_DIGEST_LIST}; do + che_hash_link "${RSA_BASENAME}_${DIGEST}.crt.pem" + done + che_hash_link "${DSA_BASENAME}.crt.pem" +) + return 0; +} + + +# === + +gen_rsa && +gen_dsa && +install && +cre_hashs + +show_status $? "${extd}Creating a new ${warn}TEST${norm} ${attn}Certificate Authority${norm} ..." +echo "${warn}password for all private keys is ${attn}${KEY_PASS}${norm}" diff -urP --exclude-from=../exclude.list ssh/tests/CA/3-cre_client_cert.sh ssh+x509c/tests/CA/3-cre_client_cert.sh --- ssh/tests/CA/3-cre_client_cert.sh Thu Jan 1 02:00:00 1970 +++ ssh+x509c/tests/CA/3-cre_client_cert.sh Mon Jun 17 23:50:25 2002 @@ -0,0 +1,229 @@ +#!/bin/sh +# Copyright (c) 2002 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# DESCRIPTION: Create client certificate(s). +# + +cd `dirname "$0"` +. ./functions +. ./config + +usage () { + cat < + -f[ile] [ssh]key_file_name + -n[name] "base" common name +EOF + exit 1 +} + +test -z "$1" && usage + +while ! test -z "$1"; do + case $1 in + -f|\ + -file) + shift + if test -z "$1"; then + usage + fi + if ! test -z "${SSH_CLIENTKEY}"; then + usage + fi + SSH_CLIENTKEY="$1" + shift + ;; + + -n|\ + -name) + shift + if test -z "$1"; then + usage + fi + if ! test -z "$SSH_CLIENT_DN_CN"; then + usage + fi + SSH_CLIENT_DN_CN="$1" + shift + ;; + + *) + usage + ;; + esac +done + +test -z "${SSH_CLIENTKEY}" && usage +test ! -r "${SSH_CLIENTKEY}" && { error_file_not_readable; exit 1; } +test -z "$SSH_CLIENT_DN_CN" && usage + + +SSH_CLIENT_DN_CN="$SSH_CLIENT_DN_CN" + + +OPENSSH_LOG="./openssh_ca.log" +cat /dev/null > .delmy +update_file .delmy "$OPENSSH_LOG" > /dev/null || exit $? + +FIFO_I_FILE="${TMPDIR}/.user-keyI.$$" +FIFO_O_FILE="${TMPDIR}/.user-keyO.$$" + +rmFIFO () { + rm -f "${FIFO_I_FILE}" + rm -f "${FIFO_O_FILE}" +} + +mkfifo "${FIFO_I_FILE}" && +chmod 600 "${FIFO_I_FILE}" && +mkfifo "${FIFO_O_FILE}" && +chmod 600 "${FIFO_O_FILE}" && +trap rmFIFO EXIT QUIT ABRT KILL TERM || exit 1 +# trap any break/exit signal and remove FILE ! +# more signals ???? + +#this is bash stuff :-( +#(!) read -p "Enter key password:" -s keypass +# -p prompt +# -s silent (!) +stty -echo +echo -n "Enter key password:"; read keypass +stty echo +echo + +echo_Ipass () { + echo "${keypass}" > "${FIFO_I_FILE}" & +} + +echo_Opass () { + echo "${keypass}" > "${FIFO_O_FILE}" & +} + +# === + +echo_SSH_CLIENT_DN () { + type="$1" + cat <> "$OPENSSH_LOG" + sync + echo_Ipass + echo_SSH_CLIENT_DN "${type}" | + $OPENSSL req -new -config "${SSH_CACFGFILE}" \ + -key "${SSH_CLIENTKEY}" \ + -passin file:"${FIFO_I_FILE}" \ + -out "${TMPDIR}/user-${type}.csr" \ + 2>> "$OPENSSH_LOG" \ + ; show_status $? "creating new ${extd}CSR${norm} for ${attn}$SSH_CLIENT_DN_CN(${type})${norm} ..." || return $? + sync +} + + +# === +cre_crt () { + local type="$1" + + echo "=== create a new CRT ===" >> "$OPENSSH_LOG" + sync + $OPENSSL ca -config "${SSH_CACFGFILE}" \ + -batch \ + -in "${TMPDIR}/user-${type}.csr" \ + -name "CA_OpenSSH_${type}" \ + -passin pass:$KEY_PASS \ + -out "${TMPDIR}/user-${type}.crt" \ + 2>> "$OPENSSH_LOG" \ + ; show_status $? "creating new ${extd}CRT${norm} for ${attn}$SSH_CLIENT_DN_CN(${type})${norm} ..." || + { status=$? + echo -n "${warn}" + grep 'ERROR:' "$OPENSSH_LOG" + echo -n "${norm}" + return $status + } + + sync + $OPENSSL verify -CAfile "${SSH_CACERTDIR}/${CAKEY_PREFIX}-${type}.crt.pem" "${TMPDIR}/user-${type}.crt" && + rm -f "${TMPDIR}/user-${type}.csr" + update_file "${TMPDIR}/user-${type}.crt" "${SSH_CLIENTKEY}-${type}.crt" +} + + +# === + +cre_OpenSSHclientCrt () { + local type="$1" + echo -n "creating ${extd}OpenSSH client certificate${norm} with signature ${attn}${type}${norm} ..." + ( cat "${SSH_CLIENTKEY}" + $OPENSSL x509 -in "${SSH_CLIENTKEY}-${type}.crt" -subject -issuer -alias + ) > "${SSH_CLIENTKEY}-${type}" && + chmod 600 "${SSH_CLIENTKEY}-${type}" \ + ; show_status $? || return $status +} + +cre_P12clientCrt () { + local type="$1" + echo -n "creating ${extd}p12 client certificate${norm} with signature ${attn}${type}${norm} ..." + echo_Ipass + echo_Opass + $OPENSSL pkcs12 \ + -passin file:"${FIFO_I_FILE}" \ + -passout file:"${FIFO_O_FILE}" \ + -in "${SSH_CLIENTKEY}-${type}" \ + -out "${SSH_CLIENTKEY}-${type}".p12 \ + -export \ + ; show_status $? || return $status +} + + +# === +cre_all2 () { + local type="$1" + cre_csr "${type}" && + cre_crt "${type}" && + cre_OpenSSHclientCrt "${type}" && + cre_P12clientCrt "${type}" +} + + +# === +cre_all () { + for DIGEST in ${RSA_DIGEST_LIST}; do + cre_all2 "rsa_${DIGEST}" || return 1 + done + cre_all2 dsa +} + +# === +cre_all + +show_status $? "${extd}Creating ${warn}TEST certificates${norm} ${extd}wich common name:${norm}${attn}$SSH_CLIENT_DN_CN${norm} ..." diff -urP --exclude-from=../exclude.list ssh/tests/CA/README ssh+x509c/tests/CA/README --- ssh/tests/CA/README Thu Jan 1 02:00:00 1970 +++ ssh+x509c/tests/CA/README Fri Jun 14 21:27:25 2002 @@ -0,0 +1,65 @@ + "HOW TO TEST?" + + Roumen Petrov + Sofia, Bulgaria + Fri Jun 14 2002 + + +NOTE: All files created after following steps are only for test environment ! + +Steps: +A.) Instalation: + Goto to .../test/CA dir + Check "config" file. + - On OpenBSD first run 'cp config.OpenBSD config' ! + - On portable version ./configure script create this file form .../config.in + Variables is config file... : TO DESCRIBE :-) + + +1.) Create "Test CA" directories and files as run: +prompt> ./1-cre_cadb.sh + + +2.) Run command: +prompt> ./2-cre_cakeys.sh + to create "Test CA" private keys and certificates. + + +3.1.) Create user key file{s} if they not exits. A sample command: +prompt> ssh-keygen -t {dsa|rsa} [-b 1024] -f PATH_TO_KEYFILEn + +3.2.) Create key certificates. + NOTE: Use key file without password. This make openssh tests more simple, otherwise you must enter password for every use of identity file. + Command is: +prompt> ./3-cre_client_cert.sh -f PATH_TO_KEYFILEn -n "Test Cert" + NOTE: "Common name" for every key file must be different, otherwise certificate creation fail. + This command create files with mask "PATH_TO_KEYFILEn-[.]", where is in format "rsa_" or "dsa". DIGEST are form variable "RSA_DIGEST_LIST" specified in "config" file. Files without extention are openssh identity files. File with .crt extention contain "text output" for user certificate. File with .p12 extention are for "Microsoft Windows keystore" + Verify "openssh_ca.log*" file[s]. + + +4.) Command "./verify.sh" is optional. + It check user certificates against "Test CA" but only when file names are in format "$HOME/.ssh/id_*.crt" + + +B.) Tests: + Run "The TEST script" (only as root!). This script use all "PATH_TO_KEYFILEn-[.]" files. + Command is: +# ./openssh_tests.sh -k PATH_TO_KEYFILEn +or +# ./openssh_tests.sh -k PATH_TO_KEYFILEn | less -r +or +# ./openssh_tests.sh -k PATH_TO_KEYFILEn > LOG_FILE +# less -r LOG_FILE +or +... + NOTE: Please read less man page for '-r' option. On Linux we can skip this option. + When all test successeded last message must be "Testing OpenSSH client certificates ... done" ! + + +C.) Test SecSH from "Microsoft Windows OSes". This is not part of document. Tip: use user *.p12 key files created in step 3.2), "Test CA" cerfificates created in step 2.) and read related SecSH client manuals. DON`T FORGET TO REMOVE entries from keystore after test. + + +D.) REMOVE "Test CA" directory (usually /etc/ssh/ca-test) and all files created in step 3.) !!! + + +E.) Enjoy ;-) diff -urP --exclude-from=../exclude.list ssh/tests/CA/config.OpenBSD ssh+x509c/tests/CA/config.OpenBSD --- ssh/tests/CA/config.OpenBSD Thu Jan 1 02:00:00 1970 +++ ssh+x509c/tests/CA/config.OpenBSD Fri Jun 14 21:30:42 2002 @@ -0,0 +1,56 @@ +# Copyright (c) 2002 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# DESCRIPTION: OpehSSH CA configuration. +# + +OPENSSL=`which openssl` +TMPDIR="/tmp" + +KEY_PASS="change_it" +CAKEY_PREFIX="catest" +RSA_BASENAME="${CAKEY_PREFIX}-rsa" +DSA_BASENAME="${CAKEY_PREFIX}-dsa" + +#RSA_DIGEST_LIST="md5 sha1 md2 md4" +#mdc2 with rsa fail !? +RSA_DIGEST_LIST="md5 sha1 md4" + + +SSH_BINDIR="/usr/bin" +SSH_SBINDIR="/usr/sbin" +SSH_SYSCONFDIR="/etc/ssh" + +SSH_CAROOT="/etc/ssh/ca-test" +SSH_CAKEYDIR="$SSH_CAROOT/keys" + +CACERTFILE="catest-bundle.crt" +SSH_CACERTDIR="$SSH_CAROOT/crt" + +CACONFIG="catest.config" +SSH_CACFGFILE="${SSH_CAROOT}/${CACONFIG}" + +SSH_CACERTDAYS=60 + +SSH_DN_C="XX" +SSH_DN_ST="World" +SSH_DN_O="OpenSSH Test Team" +SSH_DN_OU="OpenSSH Testers" + diff -urP --exclude-from=../exclude.list ssh/tests/CA/config.in ssh+x509c/tests/CA/config.in --- ssh/tests/CA/config.in Thu Jan 1 02:00:00 1970 +++ ssh+x509c/tests/CA/config.in Fri Jun 14 21:30:47 2002 @@ -0,0 +1,60 @@ +# Copyright (c) 2002 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# DESCRIPTION: OpehSSH CA configuration. +# + +OPENSSL=`which openssl` +TMPDIR="/tmp" + +KEY_PASS="change_it" +CAKEY_PREFIX="catest" +RSA_BASENAME="${CAKEY_PREFIX}-rsa" +DSA_BASENAME="${CAKEY_PREFIX}-dsa" + +#RSA_DIGEST_LIST="md5 sha1 md2 md4" +#mdc2 with rsa fail !? +RSA_DIGEST_LIST="md5 sha1 md4" + + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +sysconfdir="@sysconfdir@" + +SSH_BINDIR="@bindir@" +SSH_SBINDIR="@sbindir@" +SSH_SYSCONFDIR="@sysconfdir@" + +SSH_CAROOT="@sshcadir@-test" +SSH_CAKEYDIR="$SSH_CAROOT/keys" + +CACERTFILE="catest-bundle.crt" +SSH_CACERTDIR="$SSH_CAROOT/crt" + +CACONFIG="catest.config" +SSH_CACFGFILE="${SSH_CAROOT}/${CACONFIG}" + +SSH_CACERTDAYS=60 + +SSH_DN_C="XX" +SSH_DN_ST="World" +SSH_DN_O="OpenSSH Test Team" +SSH_DN_OU="OpenSSH Testers" + diff -urP --exclude-from=../exclude.list ssh/tests/CA/functions ssh+x509c/tests/CA/functions --- ssh/tests/CA/functions Thu Jan 1 02:00:00 1970 +++ ssh+x509c/tests/CA/functions Fri Jun 14 21:29:56 2002 @@ -0,0 +1,185 @@ +# Copyright (c) 2002 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# DESCRIPTION: Usefull functions. +# + + +# === +# +# define colors and more for echo commands +# +# \033 ascii ESCape +# \033[G move to column (linux console, xterm, not vt100) +# \033[C move columns forward but only upto last column +# \033[D move columns backward but only upto first column +# \033[A move rows up +# \033[B move rows down +# \033[1m switch bold on +# \033[31m switch red on +# \033[32m switch green on +# \033[33m switch yellow on +# \033[m switch color/bold off +# \017 exit alternate mode (xterm, vt100, linux console) +# \033[10m exit alternate mode (linux console) +# \015 carriage return (without newline) +# + +if test -z "${LINES}" -o -z "${COLUMNS}" ; then + eval `stty size 2>/dev/null | (read L C; \ + echo LINES=${L:-24} COLUMNS=${C:-80})` +fi +test ${LINES} -eq 0 && LINES=24 +test ${COLUMNS} -eq 0 && COLUMNS=80 +export LINES COLUMNS + +if test "${TERM}" != "dumb" ; then + esc=`echo -en "\033"` + extd="${esc}[1m" + warn="${esc}[1;31m" + done="${esc}[1;32m" + attn="${esc}[1;34m" + norm=`echo -en "${esc}[m\017"` + stat=`echo -en "\015${esc}[${COLUMNS}C${esc}[10D"` + + msg_done="${stat}${done}done${norm}" + msg_failed="${stat}${warn}failed${norm}" + +else + esc="" + extd="" + warn="" + done="" + attn="" + norm="" + stat="" + + msg_done="..done" + msg_failed="..failed" + +fi + + +# === +error_file_not_found () { + echo "${warn}file ${attn}${1}${warn} not found${norm}" + return 1 +} + + +# === +error_file_not_readable () { + echo "${warn}file ${attn}${1}${warn} not found or not readable${norm}" + return 1 +} + + +# === +error_dir_not_found () { + echo "${warn}directory ${attn}${1}${warn} not found${norm}" + return 1 +} + + +# === +show_status () { + if ! test -z "$2"; then + echo -ne "${2}" + fi + if test $1 == 0; then + echo "$msg_done" + else + echo "$msg_failed" + fi + return $1 +} + + +# === +getNextFileName() { + var="$1" + count=0 + while true; do + test ! -f "${var}.${count}" && break + let count=${count}+1 + done + if test ${count} -ge 10; then + echo "${warn}please remove ${attn}${var}${warn} backup files !${norm}" 1>&2 + return 33 + fi + echo $count + return 0 +} + + +# === +getNextDirName() { + var="$1" + count=0 + while true; do + test ! -d "${var}.${count}" && break + let count=${count}+1 + done + if test ${count} -ge 10; then + echo "${warn}please remove ${attn}${var}${warn} backup directories !${norm}" 1>&2 + return 33 + fi + echo $count + return 0 +} + + +# === +update_file () { + var_new="$1" + var_old="$2" + if test ! -f "${var_old}"; then + echo -n "creating file ${attn}${var_old}${norm} ... " + mv "${var_new}" "${var_old}"; show_status $? + return + fi + test -r "${var_new}" || { error_file_not_readable "${var_new}"; return 1; } + + if diff "${var_old}" "${var_new}" >/dev/null 2>&1; then + echo "no changes in ${attn}${var_old}${norm}" + rm -f "${var_new}" + return 0 + fi + + count=`getNextFileName "${var_old}"` || return $? + echo -n "saving old file as ${attn}${var_old}.${warn}${count}${norm} ... " + cp -p "${var_old}" "${var_old}.${count}"; show_status $? || return $? + + echo -n "updating file ${attn}${var_old}${norm} ... " + if test ! -w "${var_old}"; then + chmod +w "${var_old}" + not_writable="yes" + fi + cat "${var_new}" > "${var_old}"; show_status $? || return $? + if test "$not_writable" == "yes"; then + chmod -w "${var_old}" + fi + rm -f "${var_new}" + return 0 +} + + +# === +FUNCTIONS_INCLUDED="yes" diff -urP --exclude-from=../exclude.list ssh/tests/CA/openssh_tests.sh ssh+x509c/tests/CA/openssh_tests.sh --- ssh/tests/CA/openssh_tests.sh Thu Jan 1 02:00:00 1970 +++ ssh+x509c/tests/CA/openssh_tests.sh Mon Jun 17 16:13:18 2002 @@ -0,0 +1,453 @@ +#!/bin/sh +# Copyright (c) 2002 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# DESCRIPTION: Test OpenSSH client and server with x509 certificates. +# + +if test "`id -u`" != "0"; then + echo run sshd as root + echo otherwise sshd cann\`t logon client \(insufficient permitions\) + exit 2 +fi + +cd `dirname "$0"` +. ./functions +. ./config + +usage () { + cat < + -f[ile] base key_files_name as example /home/tester/.ssh/id_dsa + [-p[ort]] sshd test port (default 20022) +EOF + exit 1 +} + +test -z "$1" && usage + +while ! test -z "$1"; do + case $1 in + -f|\ + -file) + shift + if test -z "$1"; then + usage + fi + if ! test -z "${SSH_CLIENTKEY}"; then + usage + fi + SSH_CLIENTKEY="$1" + shift + ;; + + -p|\ + -port) + shift + if test -z "$1"; then + usage + fi + if ! test -z "${SSHD_PORT}"; then + usage + fi + SSHD_PORT="$1" + shift + ;; + + *) + usage + ;; + esac +done + +test -z "${SSH_CLIENTKEY}" && usage +SSHD_PORT="${SSHD_PORT:-20022}" + +TMP_DIR=${TMP_DIR:=$TMP} +test -z "$TMP_DIR" && +for D in \ + /var/tmp \ + /tmp \ +; do + test -d "$D" && TMP_DIR=$D + if test ! -z "$TMP_DIR"; then + break; + fi +done +test -z "$TMP_DIR" && { echo "${warn}NO temp dir.${norm} !"; exit 1; } + + +SSHD_LOG="$TMP_DIR/sshd_x509.log" +SSHD_PID="$TMP_DIR/.sshd_x509.pid" +SSHD_CFG="$SSH_SYSCONFDIR/sshd_config-certTests" + +SSH_ERRLOG="$TMP_DIR/.ssh_x509.err.log" +SSH_REPLY="$TMP_DIR/.ssh_x509.reply" + + +USERDIR="$HOME/.ssh" +test ! -d "$USERDIR" && ( mkdir "$USERDIR" || exit 1 ) +chmod 700 "$USERDIR" || exit 1 +AUTHORIZEDKEYSFILE="$USERDIR/authorized_keys-tests" + + +# === +runSSHdaemon() { + echo "=======================================================================" >> "$SSHD_LOG" + $SSH_SBINDIR/sshd -f "$SSH_SYSCONFDIR/sshd_config-certTests" -o pidfile=$SSHD_PID >> "$SSHD_LOG" 2>&1 || return $? + #NOTE: bug or ?: with option -e no log to stderr in daemon mode + sleep 3 +} + + +# === +killSSHdaemon() { + sleep 1 + kill -9 `cat "$SSHD_PID" 2>/dev/null` > /dev/null 2>&1 + sleep 2 + rm -f "$SSHD_PID" > /dev/null 2>&1 + rm -f "$SSHD_CFG" +} + + +# === +testEND() { + echo -e "\n*=- The END -=*" >> "$SSHD_LOG" + + rm -f "$SSH_ERRLOG" + rm -f "$SSH_REPLY" + rm -f "$AUTHORIZEDKEYSFILE" +} + +testBREAK() { + echo -e "\n*=- BREAK -=*" >> "$SSHD_LOG" + killSSHdaemon +} + +trap testBREAK INT QUIT ABRT KILL TERM || exit 1 +trap testEND EXIT || exit 1 + + +# === +creTestSSHDcfgFile() { + cat > "$SSHD_CFG" < "$SSH_ERRLOG" > "$SSH_REPLY"; status=$? + #sleep 1 + + if test "x$must_fail" = "x1"; then + if test $status -ne 0; then + status=0 + else + status=1 + fi + fi + + #show_status $status " * ${extd}${type}${norm} ${info}" + show_status $status + if test $status -ne 0; then + echo -n "${warn}" + cat "$SSH_ERRLOG"; echo -n "${norm}" + else + if test "x$must_fail" = "x1"; then + if ! grep 'Permission denied (publickey)' "$SSH_ERRLOG" > /dev/null; then + status=33 + echo -n "${warn}" + else + echo -n "${done}" + fi + cat "$SSH_ERRLOG"; echo -n "${norm}" + else + if ! grep "$msg" "$SSH_REPLY" > /dev/null; then + status=33 + echo -n "${warn}" + cat "$SSH_REPLY"; echo -n "${norm}" + fi + fi + fi + + return $status +} + + +# === +testBLOBautorization () { + local type="$1" + local identity_file="${SSH_CLIENTKEY}-${type}" + if test ! -r "$identity_file"; then + error_file_not_readable "${identity_file}"; return $? + fi + + echo " using identity file ${identity_file}" + echo " creating AuthorizedKeysFile" + $SSH_BINDIR/ssh-keygen -f "${identity_file}" -y 2>/dev/null > "$AUTHORIZEDKEYSFILE" || return $? + runTest "${type}" "${identity_file}"\ + "${extd}valid${norm} blob" || return $? + + local blob=`cat "$AUTHORIZEDKEYSFILE"` + echo $blob | cut -c 1-50 > "$AUTHORIZEDKEYSFILE" + runTest "${type}" "${identity_file}"\ + "${warn}invalid${norm} blob" "Yes" || return $? + + return 0 +} + + +# === +do_test0 () { + local status=0 + echo "=======================================================================" + echo "* ${extd}against ${attn}CACertificateFile${norm} and autorization by x509 ${attn}blob${norm}:" + creTestSSHDcfgFile + echo CACertificateFile ${SSH_CAROOT}/${CACERTFILE} >> "$SSHD_CFG" + + runSSHdaemon + for DIGEST in ${RSA_DIGEST_LIST}; do + test $status -eq 0 && testBLOBautorization "rsa_${DIGEST}"; status=$? + done + test $status -eq 0 && testBLOBautorization "dsa" ; status=$? + killSSHdaemon + return $status +} + + +# === +testDNautorizations1 () { + local type="$1" + local identity_file="${SSH_CLIENTKEY}-${type}" + if test ! -r "$identity_file"; then + error_file_not_readable "${identity_file}"; return $? + fi + + local sshkeytype="unspec" + local status=0 + + if ! sshkeytype=`$SSH_BINDIR/ssh-keygen -f "${identity_file}" -y 2>/dev/null`; then + return 33 + fi + sshkeytype=`echo "${sshkeytype}" | cut -d ' ' -f 1` + + local subject=`$OPENSSL x509 -noout -subject -in "${identity_file}" | cut -d ' ' -f 2-` || return $? + + for subtype in\ + "Subject:" \ + "SuBjecT=" \ + "sUbjecT" \ + "diStinguished name:" \ + "distinguiShed_name:" \ + "dN:" \ + ; do + echo "${sshkeytype} ${subtype} ${subject}" > "$AUTHORIZEDKEYSFILE" + runTest "${type} ${subtype}" "${identity_file}" "" || return $? + done + + for subtype in\ + "Invalid" \ + "Subject-" \ + ; do + echo "${sshkeytype} ${subtype} ${subject}" > "$AUTHORIZEDKEYSFILE" + runTest "${type} ${warn}${subtype}${norm}" "${identity_file}"\ + "autorization type" "Yes" || return $? + done + + subtype="Subject" + ( echo -n "${sshkeytype} ${subtype}" + echo "${subject}" | cut -c -40 + ) > "$AUTHORIZEDKEYSFILE" + runTest "${type} ${warn}invalid${norm} ${subtype}" "${identity_file}"\ + "" "Yes" || return $? + + return 0 +} + + +# === +do_test1 () { + local status=0 + echo "=======================================================================" + echo "* ${extd}against ${attn}CACertificateFile${norm} and autorization by x509 ${attn}'Distinguished Name'${norm}:" + creTestSSHDcfgFile + echo CACertificateFile ${SSH_CAROOT}/${CACERTFILE} >> "$SSHD_CFG" + runSSHdaemon + for DIGEST in ${RSA_DIGEST_LIST}; do + test $status -eq 0 && testDNautorizations1 "rsa_${DIGEST}"; status=$? + done + test $status -eq 0 && testDNautorizations1 "dsa" ; status=$? + killSSHdaemon + return $status +} + + +# === +testDNautorizations2 () { + local type="$1" + local must_fail="$2" + + local identity_file="${SSH_CLIENTKEY}-${type}" + if test ! -r "$identity_file"; then + error_file_not_readable "${identity_file}"; return $? + fi + + local info + if test "$must_fail" == "yes"; then + info="${warn}!${norm}" + else + info="" + fi + local sshkeytype="unspec" + local status=0 + + if ! sshkeytype=`$SSH_BINDIR/ssh-keygen -f "${identity_file}" -y 2>/dev/null`; then + return 33 + fi + sshkeytype=`echo "${sshkeytype}" | cut -d ' ' -f 1` + + local subject=`$OPENSSL x509 -noout -subject -in "${identity_file}" | cut -d ' ' -f 2-` || return $? + echo "${sshkeytype} Subject: ${subject}" > "$AUTHORIZEDKEYSFILE" + runTest "${type}" "${identity_file}"\ + "${info}" "${must_fail}" || return $? +} + + +# === +do_test_catype () { + local catype="$1" + local type="undefined" + + echo " - autorization by x509 ${attn}Subject${norm} against CA key ${attn}${catype}${norm}" + + for DIGEST in ${RSA_DIGEST_LIST}; do + type="rsa_${DIGEST}" + if test "${catype}" = "${type}"; then + testDNautorizations2 "${type}" || return $? + else + testDNautorizations2 "${type}" "yes" || return $? + fi + done + + type="dsa" + local Fname="${SSH_CLIENTKEY}-${type}" + if test "${catype}" = "${type}"; then + testDNautorizations2 "${type}" || return $? + else + testDNautorizations2 "${type}" "yes" || return $? + fi + + return 0 +} + + +# === +do_test2 () { + local status=0 + echo "=======================================================================" + echo "* ${extd}against ${attn}CACertificatePath${norm}:" + creTestSSHDcfgFile + local CRT_TEST_DIR="${SSH_CAROOT}/crt-test" + echo CACertificatePath ${CRT_TEST_DIR} >> "$SSHD_CFG" + + runSSHdaemon + if test ! -d "${CRT_TEST_DIR}"; then + mkdir "${CRT_TEST_DIR}" || return $? + fi + rm -rf "${CRT_TEST_DIR}/"* 2>/dev/null + for DIGEST in ${RSA_DIGEST_LIST}; do + if test $status -eq 0; then + local type="rsa_${DIGEST}" + HASH=`$OPENSSL x509 -in "${SSH_CACERTDIR}/${CAKEY_PREFIX}-${type}.crt.pem" -noout -hash` + ( cd "${CRT_TEST_DIR}"; ln -s "${SSH_CACERTDIR}/${CAKEY_PREFIX}-${type}.crt.pem" "$HASH".0 ) + do_test_catype "${type}"; status=$? + ( cd "${CRT_TEST_DIR}"; rm -f "$HASH".0 ) + fi + done + if test $status -eq 0; then + local type="dsa" + HASH=`$OPENSSL x509 -in "${SSH_CACERTDIR}/${CAKEY_PREFIX}-${type}.crt.pem" -noout -hash` + ( cd "${CRT_TEST_DIR}"; ln -s "${SSH_CACERTDIR}/${CAKEY_PREFIX}-${type}.crt.pem" "$HASH".0 ) + do_test_catype "${type}" ; status=$? + ( cd "${CRT_TEST_DIR}"; rm -f "$HASH".0 ) + fi + rmdir "${CRT_TEST_DIR}" + + killSSHdaemon + return $status +} + + +# === +do_all () { + echo "${extd}Testing ssh client with 'Certificate Signature Algorithm' and ...${norm}" + + echo -n > "$AUTHORIZEDKEYSFILE" + chmod 644 "$AUTHORIZEDKEYSFILE" + + echo -n > "$SSHD_LOG" + + do_test0 || return $? + do_test1 || return $? + do_test2 || return $? + + echo "=======================================================================" + return 0 +} + + +# === +do_all + +show_status $? "${extd}Testing ${warn}OpenSSH client certificates${norm} ..." diff -urP --exclude-from=../exclude.list ssh/tests/CA/verify.sh ssh+x509c/tests/CA/verify.sh --- ssh/tests/CA/verify.sh Thu Jan 1 02:00:00 1970 +++ ssh+x509c/tests/CA/verify.sh Fri Jun 14 21:29:49 2002 @@ -0,0 +1,38 @@ +#!/bin/sh +# Copyright (c) 2002 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# DESCRIPTION: Verify all $HOME/.ssh/id_*.crt files agains openssh "Test CA". +# + +cd `dirname "$0"` +. ./functions +. ./config + + +for VERIFY in \ + "$OPENSSL verify -CAfile ${SSH_CAROOT}/${CACERTFILE}" \ + "$OPENSSL verify -CApath ${SSH_CACERTDIR}" \ +; do + echo ${attn}$VERIFY ....${norm} + for F in $HOME/.ssh/id_*.crt; do + $VERIFY $F || exit 1 + done +done diff -urP --exclude-from=../exclude.list ssh/x509store.c ssh+x509c/x509store.c --- ssh/x509store.c Thu Jan 1 02:00:00 1970 +++ ssh+x509c/x509store.c Fri Jun 7 19:15:48 2002 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2002 Roumen Petrov. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "x509store.h" +#include "log.h" +#include "servconf.h" +#include "openssl/e_os.h" +#include "openssl/err.h" + + +extern ServerOptions options; +static int x509_store_loaded = 0; +static X509_STORE *x509store_ctx = NULL; +int ssh_x509_purpose = -1; + + +static int MS_CALLBACK +ssh_x509store_cb(int ok, X509_STORE_CTX *ctx) { + if (!ok) { + char buf[256]; + X509_NAME_oneline( X509_get_subject_name(ctx->current_cert), buf, sizeof(buf)); + error("ssh_x509store_cb() subject:%s\n", buf); + error("ssh_x509store_cb() error %d at %d depth lookup:%s\n", + ctx->error, + ctx->error_depth, + X509_verify_cert_error_string(ctx->error)); +#if 0 + if (ctx->error == X509_V_ERR_CERT_HAS_EXPIRED) ok=1; + /* since we are just checking the certificates, it is + * ok if they are self signed. But we should still warn + * the user. + */ + if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1; + /* Continue after extension errors too */ + if (ctx->error == X509_V_ERR_INVALID_CA) ok=1; + if (ctx->error == X509_V_ERR_PATH_LENGTH_EXCEEDED) ok=1; + if (ctx->error == X509_V_ERR_INVALID_PURPOSE) ok=1; + if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1; +#endif + } + /* + if (!v_verbose) + ERR_clear_error(); + */ + return(ok); +} + + +static void +ssh_x509store_init () { + int ret=0; + X509_LOOKUP *lookup=NULL; + x509store_ctx = X509_STORE_new(); +debug("ssh_x509store_init() begin"); + if (x509store_ctx == NULL) return; + X509_STORE_set_verify_cb_func(x509store_ctx, ssh_x509store_cb); + + lookup = X509_STORE_add_lookup(x509store_ctx, X509_LOOKUP_file()); + if (lookup == NULL) abort(); + if (options.ca_certificate_file) { + if(!X509_LOOKUP_load_file(lookup, options.ca_certificate_file, X509_FILETYPE_PEM)) { + int ecode = ERR_get_error(); + error("ssh_x509store_init(): X509_LOOKUP_load_file failed: %.200s", ERR_error_string(ecode, NULL)); + } + else { + debug2( "added to x509 store CACertificateFile=%.400s", options.ca_certificate_file); + x509_store_loaded = 1; + } + } + + lookup=X509_STORE_add_lookup(x509store_ctx, X509_LOOKUP_hash_dir()); + if (lookup == NULL) abort(); + if (options.ca_certificate_path) { + if(!X509_LOOKUP_add_dir(lookup, options.ca_certificate_path, X509_FILETYPE_PEM)) { + int ecode = ERR_get_error(); + error("ssh_x509store_init(): X509_LOOKUP_add_dir failed: %.200s", ERR_error_string(ecode, NULL)); + } + else { + debug2( "added to x509 store CACertificatePath=%.400s", options.ca_certificate_path); + x509_store_loaded = 1; + } + } + + ERR_clear_error(); +debug("ssh_x509store_init() end"); +} + + +int +ssh_x509_store_check(X509 *_cert) { + int ret = 1; + + if (!x509_store_loaded) ssh_x509store_init(); + if (x509store_ctx == NULL) { + printf("ssh_x509_store_check()-mamata\n"); + ret = 0; + } + if (ret > 0 ) { + X509_STORE_CTX *csc; + csc = X509_STORE_CTX_new(); + if (csc == NULL) { + int ecode = ERR_get_error(); + error("ssh_x509_store_check(): X509_STORE_CTX_new failed: %.200s", ERR_error_string(ecode, NULL)); + ret = 0; + } + if (ret > 0) { + X509_STORE_CTX_init(csc, x509store_ctx, _cert, NULL); + if(ssh_x509_purpose >= 0) X509_STORE_CTX_set_purpose(csc, ssh_x509_purpose); + /* + if(issuer_checks) + X509_STORE_CTX_set_flags(csc, X509_V_FLAG_CB_ISSUER_CHECK); + */ + ret = X509_verify_cert(csc); + } + X509_STORE_CTX_free(csc); + } + debug3("ssh_x509_store_check() return %d", ret); + return (ret); +} diff -urP --exclude-from=../exclude.list ssh/x509store.h ssh+x509c/x509store.h --- ssh/x509store.h Thu Jan 1 02:00:00 1970 +++ ssh+x509c/x509store.h Wed May 29 18:32:53 2002 @@ -0,0 +1,34 @@ +#ifndef X509STORE_H +#define X509STORE_H +/* + * Copyright (c) 2002 Roumen Petrov. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include + +int (*pssh_x509_store_check)(X509 *_cert); +int ssh_x509_store_check(X509 *_cert); + + +#endif /* X509STORE_H */