version 1.61, 2018/02/14 16:03:32 |
version 1.62, 2018/02/23 15:58:38 |
|
|
#include "digest.h" |
#include "digest.h" |
#define SSHKEY_INTERNAL |
#define SSHKEY_INTERNAL |
#include "sshkey.h" |
#include "sshkey.h" |
|
#include "sshkey-xmss.h" |
#include "match.h" |
#include "match.h" |
|
|
|
#include "xmss_fast.h" |
|
|
/* openssh private key file format */ |
/* openssh private key file format */ |
#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" |
#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" |
#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n" |
#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n" |
|
|
/* Version identification string for SSH v1 identity files. */ |
/* Version identification string for SSH v1 identity files. */ |
#define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n" |
#define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n" |
|
|
|
int sshkey_private_serialize_opt(const struct sshkey *key, |
|
struct sshbuf *buf, enum sshkey_serialize_rep); |
static int sshkey_from_blob_internal(struct sshbuf *buf, |
static int sshkey_from_blob_internal(struct sshbuf *buf, |
struct sshkey **keyp, int allow_cert); |
struct sshkey **keyp, int allow_cert); |
|
|
|
|
{ "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0, 0 }, |
{ "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0, 0 }, |
{ "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", |
{ "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", |
KEY_ED25519_CERT, 0, 1, 0 }, |
KEY_ED25519_CERT, 0, 1, 0 }, |
|
#ifdef WITH_XMSS |
|
{ "ssh-xmss@openssh.com", "XMSS", KEY_XMSS, 0, 0, 0 }, |
|
{ "ssh-xmss-cert-v01@openssh.com", "XMSS-CERT", |
|
KEY_XMSS_CERT, 0, 1, 0 }, |
|
#endif /* WITH_XMSS */ |
#ifdef WITH_OPENSSL |
#ifdef WITH_OPENSSL |
{ "ssh-rsa", "RSA", KEY_RSA, 0, 0, 0 }, |
{ "ssh-rsa", "RSA", KEY_RSA, 0, 0, 0 }, |
{ "rsa-sha2-256", "RSA", KEY_RSA, 0, 0, 1 }, |
{ "rsa-sha2-256", "RSA", KEY_RSA, 0, 0, 1 }, |
|
|
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
case KEY_ED25519: |
case KEY_ED25519: |
case KEY_ED25519_CERT: |
case KEY_ED25519_CERT: |
|
case KEY_XMSS: |
|
case KEY_XMSS_CERT: |
return 256; /* XXX */ |
return 256; /* XXX */ |
} |
} |
return 0; |
return 0; |
|
|
case KEY_DSA: |
case KEY_DSA: |
case KEY_ECDSA: |
case KEY_ECDSA: |
case KEY_ED25519: |
case KEY_ED25519: |
|
case KEY_XMSS: |
return 1; |
return 1; |
default: |
default: |
return 0; |
return 0; |
|
|
return KEY_ECDSA; |
return KEY_ECDSA; |
case KEY_ED25519_CERT: |
case KEY_ED25519_CERT: |
return KEY_ED25519; |
return KEY_ED25519; |
|
case KEY_XMSS_CERT: |
|
return KEY_XMSS; |
default: |
default: |
return type; |
return type; |
} |
} |
|
|
k->cert = NULL; |
k->cert = NULL; |
k->ed25519_sk = NULL; |
k->ed25519_sk = NULL; |
k->ed25519_pk = NULL; |
k->ed25519_pk = NULL; |
|
k->xmss_sk = NULL; |
|
k->xmss_pk = NULL; |
switch (k->type) { |
switch (k->type) { |
#ifdef WITH_OPENSSL |
#ifdef WITH_OPENSSL |
case KEY_RSA: |
case KEY_RSA: |
|
|
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
case KEY_ED25519: |
case KEY_ED25519: |
case KEY_ED25519_CERT: |
case KEY_ED25519_CERT: |
|
case KEY_XMSS: |
|
case KEY_XMSS_CERT: |
/* no need to prealloc */ |
/* no need to prealloc */ |
break; |
break; |
case KEY_UNSPEC: |
case KEY_UNSPEC: |
|
|
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
case KEY_ED25519: |
case KEY_ED25519: |
case KEY_ED25519_CERT: |
case KEY_ED25519_CERT: |
|
case KEY_XMSS: |
|
case KEY_XMSS_CERT: |
/* no need to prealloc */ |
/* no need to prealloc */ |
break; |
break; |
case KEY_UNSPEC: |
case KEY_UNSPEC: |
|
|
freezero(k->ed25519_sk, ED25519_SK_SZ); |
freezero(k->ed25519_sk, ED25519_SK_SZ); |
k->ed25519_sk = NULL; |
k->ed25519_sk = NULL; |
break; |
break; |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
case KEY_XMSS_CERT: |
|
freezero(k->xmss_pk, sshkey_xmss_pklen(k)); |
|
k->xmss_pk = NULL; |
|
freezero(k->xmss_sk, sshkey_xmss_sklen(k)); |
|
k->xmss_sk = NULL; |
|
sshkey_xmss_free_state(k); |
|
free(k->xmss_name); |
|
k->xmss_name = NULL; |
|
free(k->xmss_filename); |
|
k->xmss_filename = NULL; |
|
break; |
|
#endif /* WITH_XMSS */ |
case KEY_UNSPEC: |
case KEY_UNSPEC: |
break; |
break; |
default: |
default: |
|
|
case KEY_ED25519_CERT: |
case KEY_ED25519_CERT: |
return a->ed25519_pk != NULL && b->ed25519_pk != NULL && |
return a->ed25519_pk != NULL && b->ed25519_pk != NULL && |
memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0; |
memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0; |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
case KEY_XMSS_CERT: |
|
return a->xmss_pk != NULL && b->xmss_pk != NULL && |
|
sshkey_xmss_pklen(a) == sshkey_xmss_pklen(b) && |
|
memcmp(a->xmss_pk, b->xmss_pk, sshkey_xmss_pklen(a)) == 0; |
|
#endif /* WITH_XMSS */ |
default: |
default: |
return 0; |
return 0; |
} |
} |
|
|
} |
} |
|
|
static int |
static int |
to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain) |
to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain, |
|
enum sshkey_serialize_rep opts) |
{ |
{ |
int type, ret = SSH_ERR_INTERNAL_ERROR; |
int type, ret = SSH_ERR_INTERNAL_ERROR; |
const char *typename; |
const char *typename; |
|
|
case KEY_RSA_CERT: |
case KEY_RSA_CERT: |
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
case KEY_ED25519_CERT: |
case KEY_ED25519_CERT: |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS_CERT: |
|
#endif /* WITH_XMSS */ |
/* Use the existing blob */ |
/* Use the existing blob */ |
/* XXX modified flag? */ |
/* XXX modified flag? */ |
if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0) |
if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0) |
|
|
key->ed25519_pk, ED25519_PK_SZ)) != 0) |
key->ed25519_pk, ED25519_PK_SZ)) != 0) |
return ret; |
return ret; |
break; |
break; |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
if (key->xmss_name == NULL || key->xmss_pk == NULL || |
|
sshkey_xmss_pklen(key) == 0) |
|
return SSH_ERR_INVALID_ARGUMENT; |
|
if ((ret = sshbuf_put_cstring(b, typename)) != 0 || |
|
(ret = sshbuf_put_cstring(b, key->xmss_name)) != 0 || |
|
(ret = sshbuf_put_string(b, |
|
key->xmss_pk, sshkey_xmss_pklen(key))) != 0 || |
|
(ret = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0) |
|
return ret; |
|
break; |
|
#endif /* WITH_XMSS */ |
default: |
default: |
return SSH_ERR_KEY_TYPE_UNKNOWN; |
return SSH_ERR_KEY_TYPE_UNKNOWN; |
} |
} |
|
|
int |
int |
sshkey_putb(const struct sshkey *key, struct sshbuf *b) |
sshkey_putb(const struct sshkey *key, struct sshbuf *b) |
{ |
{ |
return to_blob_buf(key, b, 0); |
return to_blob_buf(key, b, 0, SSHKEY_SERIALIZE_DEFAULT); |
} |
} |
|
|
int |
int |
sshkey_puts(const struct sshkey *key, struct sshbuf *b) |
sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b, |
|
enum sshkey_serialize_rep opts) |
{ |
{ |
struct sshbuf *tmp; |
struct sshbuf *tmp; |
int r; |
int r; |
|
|
if ((tmp = sshbuf_new()) == NULL) |
if ((tmp = sshbuf_new()) == NULL) |
return SSH_ERR_ALLOC_FAIL; |
return SSH_ERR_ALLOC_FAIL; |
r = to_blob_buf(key, tmp, 0); |
r = to_blob_buf(key, tmp, 0, opts); |
if (r == 0) |
if (r == 0) |
r = sshbuf_put_stringb(b, tmp); |
r = sshbuf_put_stringb(b, tmp); |
sshbuf_free(tmp); |
sshbuf_free(tmp); |
|
|
} |
} |
|
|
int |
int |
|
sshkey_puts(const struct sshkey *key, struct sshbuf *b) |
|
{ |
|
return sshkey_puts_opts(key, b, SSHKEY_SERIALIZE_DEFAULT); |
|
} |
|
|
|
int |
sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b) |
sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b) |
{ |
{ |
return to_blob_buf(key, b, 1); |
return to_blob_buf(key, b, 1, SSHKEY_SERIALIZE_DEFAULT); |
} |
} |
|
|
static int |
static int |
to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain) |
to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain, |
|
enum sshkey_serialize_rep opts) |
{ |
{ |
int ret = SSH_ERR_INTERNAL_ERROR; |
int ret = SSH_ERR_INTERNAL_ERROR; |
size_t len; |
size_t len; |
|
|
*blobp = NULL; |
*blobp = NULL; |
if ((b = sshbuf_new()) == NULL) |
if ((b = sshbuf_new()) == NULL) |
return SSH_ERR_ALLOC_FAIL; |
return SSH_ERR_ALLOC_FAIL; |
if ((ret = to_blob_buf(key, b, force_plain)) != 0) |
if ((ret = to_blob_buf(key, b, force_plain, opts)) != 0) |
goto out; |
goto out; |
len = sshbuf_len(b); |
len = sshbuf_len(b); |
if (lenp != NULL) |
if (lenp != NULL) |
|
|
int |
int |
sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp) |
sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp) |
{ |
{ |
return to_blob(key, blobp, lenp, 0); |
return to_blob(key, blobp, lenp, 0, SSHKEY_SERIALIZE_DEFAULT); |
} |
} |
|
|
int |
int |
sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp) |
sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp) |
{ |
{ |
return to_blob(key, blobp, lenp, 1); |
return to_blob(key, blobp, lenp, 1, SSHKEY_SERIALIZE_DEFAULT); |
} |
} |
|
|
int |
int |
|
|
r = SSH_ERR_INVALID_ARGUMENT; |
r = SSH_ERR_INVALID_ARGUMENT; |
goto out; |
goto out; |
} |
} |
if ((r = to_blob(k, &blob, &blob_len, 1)) != 0) |
if ((r = to_blob(k, &blob, &blob_len, 1, SSHKEY_SERIALIZE_DEFAULT)) |
|
!= 0) |
goto out; |
goto out; |
if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) { |
if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) { |
r = SSH_ERR_ALLOC_FAIL; |
r = SSH_ERR_ALLOC_FAIL; |
|
|
case KEY_ECDSA_CERT: |
case KEY_ECDSA_CERT: |
case KEY_RSA_CERT: |
case KEY_RSA_CERT: |
case KEY_ED25519_CERT: |
case KEY_ED25519_CERT: |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
case KEY_XMSS_CERT: |
|
#endif /* WITH_XMSS */ |
space = strchr(cp, ' '); |
space = strchr(cp, ' '); |
if (space == NULL) |
if (space == NULL) |
return SSH_ERR_INVALID_FORMAT; |
return SSH_ERR_INVALID_FORMAT; |
|
|
/* XXX */ |
/* XXX */ |
#endif |
#endif |
break; |
break; |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
free(ret->xmss_pk); |
|
ret->xmss_pk = k->xmss_pk; |
|
k->xmss_pk = NULL; |
|
free(ret->xmss_state); |
|
ret->xmss_state = k->xmss_state; |
|
k->xmss_state = NULL; |
|
free(ret->xmss_name); |
|
ret->xmss_name = k->xmss_name; |
|
k->xmss_name = NULL; |
|
free(ret->xmss_filename); |
|
ret->xmss_filename = k->xmss_filename; |
|
k->xmss_filename = NULL; |
|
#ifdef DEBUG_PK |
|
/* XXX */ |
|
#endif |
|
break; |
|
#endif /* WITH_XMSS */ |
} |
} |
*cpp = ep; |
*cpp = ep; |
retval = 0; |
retval = 0; |
|
|
crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk); |
crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk); |
ret = 0; |
ret = 0; |
break; |
break; |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
ret = sshkey_xmss_generate_private_key(k, bits); |
|
break; |
|
#endif /* WITH_XMSS */ |
#ifdef WITH_OPENSSL |
#ifdef WITH_OPENSSL |
case KEY_DSA: |
case KEY_DSA: |
ret = dsa_generate_private_key(bits, &k->dsa); |
ret = dsa_generate_private_key(bits, &k->dsa); |
|
|
memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); |
memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); |
} |
} |
break; |
break; |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
case KEY_XMSS_CERT: |
|
if ((n = sshkey_new(k->type)) == NULL) |
|
return SSH_ERR_ALLOC_FAIL; |
|
if ((ret = sshkey_xmss_init(n, k->xmss_name)) != 0) { |
|
sshkey_free(n); |
|
return ret; |
|
} |
|
if (k->xmss_pk != NULL) { |
|
size_t pklen = sshkey_xmss_pklen(k); |
|
if (pklen == 0 || sshkey_xmss_pklen(n) != pklen) { |
|
sshkey_free(n); |
|
return SSH_ERR_INTERNAL_ERROR; |
|
} |
|
if ((n->xmss_pk = malloc(pklen)) == NULL) { |
|
sshkey_free(n); |
|
return SSH_ERR_ALLOC_FAIL; |
|
} |
|
memcpy(n->xmss_pk, k->xmss_pk, pklen); |
|
} |
|
break; |
|
#endif /* WITH_XMSS */ |
default: |
default: |
return SSH_ERR_KEY_TYPE_UNKNOWN; |
return SSH_ERR_KEY_TYPE_UNKNOWN; |
} |
} |
|
|
int allow_cert) |
int allow_cert) |
{ |
{ |
int type, ret = SSH_ERR_INTERNAL_ERROR; |
int type, ret = SSH_ERR_INTERNAL_ERROR; |
char *ktype = NULL, *curve = NULL; |
char *ktype = NULL, *curve = NULL, *xmss_name = NULL; |
struct sshkey *key = NULL; |
struct sshkey *key = NULL; |
size_t len; |
size_t len; |
u_char *pk = NULL; |
u_char *pk = NULL; |
|
|
key->ed25519_pk = pk; |
key->ed25519_pk = pk; |
pk = NULL; |
pk = NULL; |
break; |
break; |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS_CERT: |
|
/* Skip nonce */ |
|
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { |
|
ret = SSH_ERR_INVALID_FORMAT; |
|
goto out; |
|
} |
|
/* FALLTHROUGH */ |
|
case KEY_XMSS: |
|
if ((ret = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0) |
|
goto out; |
|
if ((key = sshkey_new(type)) == NULL) { |
|
ret = SSH_ERR_ALLOC_FAIL; |
|
goto out; |
|
} |
|
if ((ret = sshkey_xmss_init(key, xmss_name)) != 0) |
|
goto out; |
|
if ((ret = sshbuf_get_string(b, &pk, &len)) != 0) |
|
goto out; |
|
if (len == 0 || len != sshkey_xmss_pklen(key)) { |
|
ret = SSH_ERR_INVALID_FORMAT; |
|
goto out; |
|
} |
|
key->xmss_pk = pk; |
|
pk = NULL; |
|
if (type != KEY_XMSS_CERT && |
|
(ret = sshkey_xmss_deserialize_pk_info(key, b)) != 0) |
|
goto out; |
|
break; |
|
#endif /* WITH_XMSS */ |
case KEY_UNSPEC: |
case KEY_UNSPEC: |
default: |
default: |
ret = SSH_ERR_KEY_TYPE_UNKNOWN; |
ret = SSH_ERR_KEY_TYPE_UNKNOWN; |
|
|
out: |
out: |
sshbuf_free(copy); |
sshbuf_free(copy); |
sshkey_free(key); |
sshkey_free(key); |
|
free(xmss_name); |
free(ktype); |
free(ktype); |
free(curve); |
free(curve); |
free(pk); |
free(pk); |
|
|
case KEY_ED25519: |
case KEY_ED25519: |
case KEY_ED25519_CERT: |
case KEY_ED25519_CERT: |
return ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat); |
return ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat); |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
case KEY_XMSS_CERT: |
|
return ssh_xmss_sign(key, sigp, lenp, data, datalen, compat); |
|
#endif /* WITH_XMSS */ |
default: |
default: |
return SSH_ERR_KEY_TYPE_UNKNOWN; |
return SSH_ERR_KEY_TYPE_UNKNOWN; |
} |
} |
|
|
case KEY_ED25519: |
case KEY_ED25519: |
case KEY_ED25519_CERT: |
case KEY_ED25519_CERT: |
return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat); |
return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat); |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
case KEY_XMSS_CERT: |
|
return ssh_xmss_verify(key, sig, siglen, data, dlen, compat); |
|
#endif /* WITH_XMSS */ |
default: |
default: |
return SSH_ERR_KEY_TYPE_UNKNOWN; |
return SSH_ERR_KEY_TYPE_UNKNOWN; |
} |
} |
|
|
pk->rsa = NULL; |
pk->rsa = NULL; |
pk->ed25519_pk = NULL; |
pk->ed25519_pk = NULL; |
pk->ed25519_sk = NULL; |
pk->ed25519_sk = NULL; |
|
pk->xmss_pk = NULL; |
|
pk->xmss_sk = NULL; |
|
|
switch (k->type) { |
switch (k->type) { |
#ifdef WITH_OPENSSL |
#ifdef WITH_OPENSSL |
|
|
memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); |
memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); |
} |
} |
break; |
break; |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS_CERT: |
|
if ((ret = sshkey_cert_copy(k, pk)) != 0) |
|
goto fail; |
|
/* FALLTHROUGH */ |
|
case KEY_XMSS: |
|
if ((ret = sshkey_xmss_init(pk, k->xmss_name)) != 0) |
|
goto fail; |
|
if (k->xmss_pk != NULL) { |
|
size_t pklen = sshkey_xmss_pklen(k); |
|
|
|
if (pklen == 0 || sshkey_xmss_pklen(pk) != pklen) { |
|
ret = SSH_ERR_INTERNAL_ERROR; |
|
goto fail; |
|
} |
|
if ((pk->xmss_pk = malloc(pklen)) == NULL) { |
|
ret = SSH_ERR_ALLOC_FAIL; |
|
goto fail; |
|
} |
|
memcpy(pk->xmss_pk, k->xmss_pk, pklen); |
|
} |
|
break; |
|
#endif /* WITH_XMSS */ |
default: |
default: |
ret = SSH_ERR_KEY_TYPE_UNKNOWN; |
ret = SSH_ERR_KEY_TYPE_UNKNOWN; |
fail: |
fail: |
|
|
case KEY_ED25519: |
case KEY_ED25519: |
newtype = KEY_ED25519_CERT; |
newtype = KEY_ED25519_CERT; |
break; |
break; |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
newtype = KEY_XMSS_CERT; |
|
break; |
|
#endif /* WITH_XMSS */ |
default: |
default: |
return SSH_ERR_INVALID_ARGUMENT; |
return SSH_ERR_INVALID_ARGUMENT; |
} |
} |
|
|
k->ed25519_pk, ED25519_PK_SZ)) != 0) |
k->ed25519_pk, ED25519_PK_SZ)) != 0) |
goto out; |
goto out; |
break; |
break; |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS_CERT: |
|
if (k->xmss_name == NULL) { |
|
ret = SSH_ERR_INVALID_ARGUMENT; |
|
goto out; |
|
} |
|
if ((ret = sshbuf_put_cstring(cert, k->xmss_name)) || |
|
(ret = sshbuf_put_string(cert, |
|
k->xmss_pk, sshkey_xmss_pklen(k))) != 0) |
|
goto out; |
|
break; |
|
#endif /* WITH_XMSS */ |
default: |
default: |
ret = SSH_ERR_INVALID_ARGUMENT; |
ret = SSH_ERR_INVALID_ARGUMENT; |
goto out; |
goto out; |
|
|
} |
} |
|
|
int |
int |
sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b) |
sshkey_private_serialize_opt(const struct sshkey *key, struct sshbuf *b, |
|
enum sshkey_serialize_rep opts) |
{ |
{ |
int r = SSH_ERR_INTERNAL_ERROR; |
int r = SSH_ERR_INTERNAL_ERROR; |
|
|
|
|
ED25519_SK_SZ)) != 0) |
ED25519_SK_SZ)) != 0) |
goto out; |
goto out; |
break; |
break; |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
if (key->xmss_name == NULL) { |
|
r = SSH_ERR_INVALID_ARGUMENT; |
|
goto out; |
|
} |
|
if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 || |
|
(r = sshbuf_put_string(b, key->xmss_pk, |
|
sshkey_xmss_pklen(key))) != 0 || |
|
(r = sshbuf_put_string(b, key->xmss_sk, |
|
sshkey_xmss_sklen(key))) != 0 || |
|
(r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0) |
|
goto out; |
|
break; |
|
case KEY_XMSS_CERT: |
|
if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0 || |
|
key->xmss_name == NULL) { |
|
r = SSH_ERR_INVALID_ARGUMENT; |
|
goto out; |
|
} |
|
if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || |
|
(r = sshbuf_put_cstring(b, key->xmss_name)) != 0 || |
|
(r = sshbuf_put_string(b, key->xmss_pk, |
|
sshkey_xmss_pklen(key))) != 0 || |
|
(r = sshbuf_put_string(b, key->xmss_sk, |
|
sshkey_xmss_sklen(key))) != 0 || |
|
(r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0) |
|
goto out; |
|
break; |
|
#endif /* WITH_XMSS */ |
default: |
default: |
r = SSH_ERR_INVALID_ARGUMENT; |
r = SSH_ERR_INVALID_ARGUMENT; |
goto out; |
goto out; |
|
|
} |
} |
|
|
int |
int |
|
sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b) |
|
{ |
|
return sshkey_private_serialize_opt(key, b, |
|
SSHKEY_SERIALIZE_DEFAULT); |
|
} |
|
|
|
int |
sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) |
sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) |
{ |
{ |
char *tname = NULL, *curve = NULL; |
char *tname = NULL, *curve = NULL, *xmss_name = NULL; |
struct sshkey *k = NULL; |
struct sshkey *k = NULL; |
size_t pklen = 0, sklen = 0; |
size_t pklen = 0, sklen = 0; |
int type, r = SSH_ERR_INTERNAL_ERROR; |
int type, r = SSH_ERR_INTERNAL_ERROR; |
u_char *ed25519_pk = NULL, *ed25519_sk = NULL; |
u_char *ed25519_pk = NULL, *ed25519_sk = NULL; |
|
u_char *xmss_pk = NULL, *xmss_sk = NULL; |
#ifdef WITH_OPENSSL |
#ifdef WITH_OPENSSL |
BIGNUM *exponent = NULL; |
BIGNUM *exponent = NULL; |
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
|
|
k->ed25519_sk = ed25519_sk; |
k->ed25519_sk = ed25519_sk; |
ed25519_pk = ed25519_sk = NULL; |
ed25519_pk = ed25519_sk = NULL; |
break; |
break; |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
if ((k = sshkey_new_private(type)) == NULL) { |
|
r = SSH_ERR_ALLOC_FAIL; |
|
goto out; |
|
} |
|
if ((r = sshbuf_get_cstring(buf, &xmss_name, NULL)) != 0 || |
|
(r = sshkey_xmss_init(k, xmss_name)) != 0 || |
|
(r = sshbuf_get_string(buf, &xmss_pk, &pklen)) != 0 || |
|
(r = sshbuf_get_string(buf, &xmss_sk, &sklen)) != 0) |
|
goto out; |
|
if (pklen != sshkey_xmss_pklen(k) || |
|
sklen != sshkey_xmss_sklen(k)) { |
|
r = SSH_ERR_INVALID_FORMAT; |
|
goto out; |
|
} |
|
k->xmss_pk = xmss_pk; |
|
k->xmss_sk = xmss_sk; |
|
xmss_pk = xmss_sk = NULL; |
|
/* optional internal state */ |
|
if ((r = sshkey_xmss_deserialize_state_opt(k, buf)) != 0) |
|
goto out; |
|
break; |
|
case KEY_XMSS_CERT: |
|
if ((r = sshkey_froms(buf, &k)) != 0 || |
|
(r = sshkey_add_private(k)) != 0 || |
|
(r = sshbuf_get_string(buf, &xmss_pk, &pklen)) != 0 || |
|
(r = sshbuf_get_string(buf, &xmss_sk, &sklen)) != 0) |
|
goto out; |
|
if (pklen != sshkey_xmss_pklen(k) || |
|
sklen != sshkey_xmss_sklen(k)) { |
|
r = SSH_ERR_INVALID_FORMAT; |
|
goto out; |
|
} |
|
k->xmss_pk = xmss_pk; |
|
k->xmss_sk = xmss_sk; |
|
xmss_pk = xmss_sk = NULL; |
|
/* optional internal state */ |
|
if ((r = sshkey_xmss_deserialize_state_opt(k, buf)) != 0) |
|
goto out; |
|
break; |
|
#endif /* WITH_XMSS */ |
default: |
default: |
r = SSH_ERR_KEY_TYPE_UNKNOWN; |
r = SSH_ERR_KEY_TYPE_UNKNOWN; |
goto out; |
goto out; |
|
|
sshkey_free(k); |
sshkey_free(k); |
freezero(ed25519_pk, pklen); |
freezero(ed25519_pk, pklen); |
freezero(ed25519_sk, sklen); |
freezero(ed25519_sk, sklen); |
|
free(xmss_name); |
|
freezero(xmss_pk, pklen); |
|
freezero(xmss_sk, sklen); |
return r; |
return r; |
} |
} |
|
|
|
|
goto out; |
goto out; |
|
|
/* append private key and comment*/ |
/* append private key and comment*/ |
if ((r = sshkey_private_serialize(prv, encrypted)) != 0 || |
if ((r = sshkey_private_serialize_opt(prv, encrypted, |
|
SSHKEY_SERIALIZE_FULL)) != 0 || |
(r = sshbuf_put_cstring(encrypted, comment)) != 0) |
(r = sshbuf_put_cstring(encrypted, comment)) != 0) |
goto out; |
goto out; |
|
|
|
|
passphrase, comment); |
passphrase, comment); |
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
case KEY_ED25519: |
case KEY_ED25519: |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
#endif /* WITH_XMSS */ |
return sshkey_private_to_blob2(key, blob, passphrase, |
return sshkey_private_to_blob2(key, blob, passphrase, |
comment, new_format_cipher, new_format_rounds); |
comment, new_format_cipher, new_format_rounds); |
default: |
default: |
|
|
passphrase, keyp); |
passphrase, keyp); |
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
case KEY_ED25519: |
case KEY_ED25519: |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
#endif /* WITH_XMSS */ |
return sshkey_parse_private2(blob, type, passphrase, |
return sshkey_parse_private2(blob, type, passphrase, |
keyp, commentp); |
keyp, commentp); |
case KEY_UNSPEC: |
case KEY_UNSPEC: |
|
|
return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC, |
return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC, |
passphrase, keyp, commentp); |
passphrase, keyp, commentp); |
} |
} |
|
|
|
#ifdef WITH_XMSS |
|
/* |
|
* serialize the key with the current state and forward the state |
|
* maxsign times. |
|
*/ |
|
int |
|
sshkey_private_serialize_maxsign(const struct sshkey *k, struct sshbuf *b, |
|
u_int32_t maxsign, sshkey_printfn *pr) |
|
{ |
|
int r, rupdate; |
|
|
|
if (maxsign == 0 || |
|
sshkey_type_plain(k->type) != KEY_XMSS) |
|
return sshkey_private_serialize_opt(k, b, |
|
SSHKEY_SERIALIZE_DEFAULT); |
|
if ((r = sshkey_xmss_get_state(k, pr)) != 0 || |
|
(r = sshkey_private_serialize_opt(k, b, |
|
SSHKEY_SERIALIZE_STATE)) != 0 || |
|
(r = sshkey_xmss_forward_state(k, maxsign)) != 0) |
|
goto out; |
|
r = 0; |
|
out: |
|
if ((rupdate = sshkey_xmss_update_state(k, pr)) != 0) { |
|
if (r == 0) |
|
r = rupdate; |
|
} |
|
return r; |
|
} |
|
|
|
u_int32_t |
|
sshkey_signatures_left(const struct sshkey *k) |
|
{ |
|
if (sshkey_type_plain(k->type) == KEY_XMSS) |
|
return sshkey_xmss_signatures_left(k); |
|
return 0; |
|
} |
|
|
|
int |
|
sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign) |
|
{ |
|
if (sshkey_type_plain(k->type) != KEY_XMSS) |
|
return SSH_ERR_INVALID_ARGUMENT; |
|
return sshkey_xmss_enable_maxsign(k, maxsign); |
|
} |
|
|
|
int |
|
sshkey_set_filename(struct sshkey *k, const char *filename) |
|
{ |
|
if (k == NULL) |
|
return SSH_ERR_INVALID_ARGUMENT; |
|
if (sshkey_type_plain(k->type) != KEY_XMSS) |
|
return 0; |
|
if (filename == NULL) |
|
return SSH_ERR_INVALID_ARGUMENT; |
|
if ((k->xmss_filename = strdup(filename)) == NULL) |
|
return SSH_ERR_ALLOC_FAIL; |
|
return 0; |
|
} |
|
#else |
|
int |
|
sshkey_private_serialize_maxsign(const struct sshkey *k, struct sshbuf *b, |
|
u_int32_t maxsign, sshkey_printfn *pr) |
|
{ |
|
return sshkey_private_serialize_opt(k, b, SSHKEY_SERIALIZE_DEFAULT); |
|
} |
|
|
|
u_int32_t |
|
sshkey_signatures_left(const struct sshkey *k) |
|
{ |
|
return 0; |
|
} |
|
|
|
int |
|
sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign) |
|
{ |
|
return SSH_ERR_INVALID_ARGUMENT; |
|
} |
|
|
|
int |
|
sshkey_set_filename(struct sshkey *k, const char *filename) |
|
{ |
|
if (k == NULL) |
|
return SSH_ERR_INVALID_ARGUMENT; |
|
return 0; |
|
} |
|
#endif /* WITH_XMSS */ |