+
+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;
+
+ 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);
+ if (lenp != NULL)
+ *lenp = len;
+ if (blobp != NULL) {
+ *blobp = xmalloc(len);
+ memcpy(*blobp, buffer_ptr(&b), len);
+ }
+ memset(buffer_ptr(&b), 0, len);
+ buffer_free(&b);
+ 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);
+}