version 1.13, 2015/01/16 06:40:12 |
version 1.14, 2015/01/26 02:59:11 |
|
|
/* 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" |
|
|
static int sshkey_from_blob_internal(const u_char *blob, size_t blen, |
static int sshkey_from_blob_internal(struct sshbuf *buf, |
struct sshkey **keyp, int allow_cert); |
struct sshkey **keyp, int allow_cert); |
|
|
/* Supported key types */ |
/* Supported key types */ |
|
|
} |
} |
|
|
int |
int |
sshkey_to_blob_buf(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); |
} |
} |
|
|
int |
int |
sshkey_plain_to_blob_buf(const struct sshkey *key, struct sshbuf *b) |
sshkey_puts(const struct sshkey *key, struct sshbuf *b) |
{ |
{ |
|
struct sshbuf *tmp; |
|
int r; |
|
|
|
if ((tmp = sshbuf_new()) == NULL) |
|
return SSH_ERR_ALLOC_FAIL; |
|
r = to_blob_buf(key, tmp, 0); |
|
if (r == 0) |
|
r = sshbuf_put_stringb(b, tmp); |
|
sshbuf_free(tmp); |
|
return r; |
|
} |
|
|
|
int |
|
sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b) |
|
{ |
return to_blob_buf(key, b, 1); |
return to_blob_buf(key, b, 1); |
} |
} |
|
|
|
|
ret = SSH_ERR_ALLOC_FAIL; |
ret = SSH_ERR_ALLOC_FAIL; |
goto out; |
goto out; |
} |
} |
if ((ret = sshkey_to_blob_buf(key, bb)) != 0) |
if ((ret = sshkey_putb(key, bb)) != 0) |
goto out; |
goto out; |
if ((uu = sshbuf_dtob64(bb)) == NULL) { |
if ((uu = sshbuf_dtob64(bb)) == NULL) { |
ret = SSH_ERR_ALLOC_FAIL; |
ret = SSH_ERR_ALLOC_FAIL; |
|
|
} |
} |
|
|
static int |
static int |
cert_parse(struct sshbuf *b, struct sshkey *key, const u_char *blob, |
cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf) |
size_t blen) |
|
{ |
{ |
struct sshbuf *principals = NULL, *crit = NULL, *exts = NULL; |
struct sshbuf *principals = NULL, *crit = NULL; |
u_char *sig_key = NULL, *sig = NULL; |
struct sshbuf *exts = NULL, *ca = NULL; |
size_t signed_len = 0, sklen = 0, slen = 0, kidlen = 0; |
u_char *sig = NULL; |
|
size_t signed_len = 0, slen = 0, kidlen = 0; |
int ret = SSH_ERR_INTERNAL_ERROR; |
int ret = SSH_ERR_INTERNAL_ERROR; |
int v00 = sshkey_cert_is_legacy(key); |
int v00 = sshkey_cert_is_legacy(key); |
|
|
/* Copy the entire key blob for verification and later serialisation */ |
/* Copy the entire key blob for verification and later serialisation */ |
if ((ret = sshbuf_put(key->cert->certblob, blob, blen)) != 0) |
if ((ret = sshbuf_putb(key->cert->certblob, certbuf)) != 0) |
return ret; |
return ret; |
|
|
if ((!v00 && (ret = sshbuf_get_u64(b, &key->cert->serial)) != 0) || |
if ((!v00 && (ret = sshbuf_get_u64(b, &key->cert->serial)) != 0) || |
|
|
(!v00 && (ret = sshbuf_froms(b, &exts)) != 0) || |
(!v00 && (ret = sshbuf_froms(b, &exts)) != 0) || |
(v00 && (ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0) || |
(v00 && (ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0) || |
(ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0 || |
(ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0 || |
(ret = sshbuf_get_string(b, &sig_key, &sklen)) != 0) { |
(ret = sshbuf_froms(b, &ca)) != 0) { |
/* XXX debug print error for ret */ |
/* XXX debug print error for ret */ |
ret = SSH_ERR_INVALID_FORMAT; |
ret = SSH_ERR_INVALID_FORMAT; |
goto out; |
goto out; |
|
|
} |
} |
|
|
/* Parse CA key and check signature */ |
/* Parse CA key and check signature */ |
if (sshkey_from_blob_internal(sig_key, sklen, |
if (sshkey_from_blob_internal(ca, &key->cert->signature_key, 0) != 0) { |
&key->cert->signature_key, 0) != 0) { |
|
ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; |
ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; |
goto out; |
goto out; |
} |
} |
|
|
/* Success */ |
/* Success */ |
ret = 0; |
ret = 0; |
out: |
out: |
|
sshbuf_free(ca); |
sshbuf_free(crit); |
sshbuf_free(crit); |
sshbuf_free(exts); |
sshbuf_free(exts); |
sshbuf_free(principals); |
sshbuf_free(principals); |
free(sig_key); |
|
free(sig); |
free(sig); |
return ret; |
return ret; |
} |
} |
|
|
static int |
static int |
sshkey_from_blob_internal(const u_char *blob, size_t blen, |
sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, |
struct sshkey **keyp, int allow_cert) |
int allow_cert) |
{ |
{ |
struct sshbuf *b = NULL; |
|
int type, ret = SSH_ERR_INTERNAL_ERROR; |
int type, ret = SSH_ERR_INTERNAL_ERROR; |
char *ktype = NULL, *curve = NULL; |
char *ktype = NULL, *curve = NULL; |
struct sshkey *key = NULL; |
struct sshkey *key = NULL; |
size_t len; |
size_t len; |
u_char *pk = NULL; |
u_char *pk = NULL; |
|
struct sshbuf *copy; |
#ifdef WITH_OPENSSL |
#ifdef WITH_OPENSSL |
EC_POINT *q = NULL; |
EC_POINT *q = NULL; |
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
|
|
#ifdef DEBUG_PK /* XXX */ |
#ifdef DEBUG_PK /* XXX */ |
dump_base64(stderr, blob, blen); |
sshbuf_dump(b, stderr); |
#endif |
#endif |
*keyp = NULL; |
*keyp = NULL; |
if ((b = sshbuf_from(blob, blen)) == NULL) |
if ((copy = sshbuf_fromb(b)) == NULL) { |
return SSH_ERR_ALLOC_FAIL; |
ret = SSH_ERR_ALLOC_FAIL; |
|
goto out; |
|
} |
if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { |
if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { |
ret = SSH_ERR_INVALID_FORMAT; |
ret = SSH_ERR_INVALID_FORMAT; |
goto out; |
goto out; |
|
|
switch (type) { |
switch (type) { |
#ifdef WITH_OPENSSL |
#ifdef WITH_OPENSSL |
case KEY_RSA_CERT: |
case KEY_RSA_CERT: |
|
/* Skip nonce */ |
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { |
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { |
ret = SSH_ERR_INVALID_FORMAT; |
ret = SSH_ERR_INVALID_FORMAT; |
goto out; |
goto out; |
|
|
#endif |
#endif |
break; |
break; |
case KEY_DSA_CERT: |
case KEY_DSA_CERT: |
|
/* Skip nonce */ |
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { |
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { |
ret = SSH_ERR_INVALID_FORMAT; |
ret = SSH_ERR_INVALID_FORMAT; |
goto out; |
goto out; |
|
|
#endif |
#endif |
break; |
break; |
case KEY_ECDSA_CERT: |
case KEY_ECDSA_CERT: |
|
/* Skip nonce */ |
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { |
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { |
ret = SSH_ERR_INVALID_FORMAT; |
ret = SSH_ERR_INVALID_FORMAT; |
goto out; |
goto out; |
|
|
break; |
break; |
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
case KEY_ED25519_CERT: |
case KEY_ED25519_CERT: |
|
/* Skip nonce */ |
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { |
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { |
ret = SSH_ERR_INVALID_FORMAT; |
ret = SSH_ERR_INVALID_FORMAT; |
goto out; |
goto out; |
|
|
} |
} |
|
|
/* Parse certificate potion */ |
/* Parse certificate potion */ |
if (sshkey_is_cert(key) && |
if (sshkey_is_cert(key) && (ret = cert_parse(b, key, copy)) != 0) |
(ret = cert_parse(b, key, blob, blen)) != 0) |
|
goto out; |
goto out; |
|
|
if (key != NULL && sshbuf_len(b) != 0) { |
if (key != NULL && sshbuf_len(b) != 0) { |
|
|
*keyp = key; |
*keyp = key; |
key = NULL; |
key = NULL; |
out: |
out: |
sshbuf_free(b); |
sshbuf_free(copy); |
sshkey_free(key); |
sshkey_free(key); |
free(ktype); |
free(ktype); |
free(curve); |
free(curve); |
|
|
int |
int |
sshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp) |
sshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp) |
{ |
{ |
return sshkey_from_blob_internal(blob, blen, keyp, 1); |
struct sshbuf *b; |
|
int r; |
|
|
|
if ((b = sshbuf_from(blob, blen)) == NULL) |
|
return SSH_ERR_ALLOC_FAIL; |
|
r = sshkey_from_blob_internal(b, keyp, 1); |
|
sshbuf_free(b); |
|
return r; |
} |
} |
|
|
int |
int |
|
sshkey_fromb(struct sshbuf *b, struct sshkey **keyp) |
|
{ |
|
return sshkey_from_blob_internal(b, keyp, 1); |
|
} |
|
|
|
int |
|
sshkey_froms(struct sshbuf *buf, struct sshkey **keyp) |
|
{ |
|
struct sshbuf *b; |
|
int r; |
|
|
|
if ((r = sshbuf_froms(buf, &b)) != 0) |
|
return r; |
|
r = sshkey_from_blob_internal(b, keyp, 1); |
|
sshbuf_free(b); |
|
return r; |
|
} |
|
|
|
int |
sshkey_sign(const struct sshkey *key, |
sshkey_sign(const struct sshkey *key, |
u_char **sigp, size_t *lenp, |
u_char **sigp, size_t *lenp, |
const u_char *data, size_t datalen, u_int compat) |
const u_char *data, size_t datalen, u_int compat) |
|
|
{ |
{ |
char *tname = NULL, *curve = NULL; |
char *tname = NULL, *curve = NULL; |
struct sshkey *k = NULL; |
struct sshkey *k = NULL; |
const u_char *cert; |
size_t pklen = 0, sklen = 0; |
size_t len, 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; |
#ifdef WITH_OPENSSL |
#ifdef WITH_OPENSSL |
|
|
break; |
break; |
case KEY_DSA_CERT_V00: |
case KEY_DSA_CERT_V00: |
case KEY_DSA_CERT: |
case KEY_DSA_CERT: |
if ((r = sshbuf_get_string_direct(buf, &cert, &len)) != 0 || |
if ((r = sshkey_froms(buf, &k)) != 0 || |
(r = sshkey_from_blob(cert, len, &k)) != 0 || |
|
(r = sshkey_add_private(k)) != 0 || |
(r = sshkey_add_private(k)) != 0 || |
(r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0) |
(r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0) |
goto out; |
goto out; |
|
|
r = SSH_ERR_LIBCRYPTO_ERROR; |
r = SSH_ERR_LIBCRYPTO_ERROR; |
goto out; |
goto out; |
} |
} |
if ((r = sshbuf_get_string_direct(buf, &cert, &len)) != 0 || |
if ((r = sshkey_froms(buf, &k)) != 0 || |
(r = sshkey_from_blob(cert, len, &k)) != 0 || |
|
(r = sshkey_add_private(k)) != 0 || |
(r = sshkey_add_private(k)) != 0 || |
(r = sshbuf_get_bignum2(buf, exponent)) != 0) |
(r = sshbuf_get_bignum2(buf, exponent)) != 0) |
goto out; |
goto out; |
|
|
break; |
break; |
case KEY_RSA_CERT_V00: |
case KEY_RSA_CERT_V00: |
case KEY_RSA_CERT: |
case KEY_RSA_CERT: |
if ((r = sshbuf_get_string_direct(buf, &cert, &len)) != 0 || |
if ((r = sshkey_froms(buf, &k)) != 0 || |
(r = sshkey_from_blob(cert, len, &k)) != 0 || |
|
(r = sshkey_add_private(k)) != 0 || |
(r = sshkey_add_private(k)) != 0 || |
(r = sshbuf_get_bignum2(buf, k->rsa->d) != 0) || |
(r = sshbuf_get_bignum2(buf, k->rsa->d) != 0) || |
(r = sshbuf_get_bignum2(buf, k->rsa->iqmp) != 0) || |
(r = sshbuf_get_bignum2(buf, k->rsa->iqmp) != 0) || |
|
|
ed25519_pk = ed25519_sk = NULL; |
ed25519_pk = ed25519_sk = NULL; |
break; |
break; |
case KEY_ED25519_CERT: |
case KEY_ED25519_CERT: |
if ((r = sshbuf_get_string_direct(buf, &cert, &len)) != 0 || |
if ((r = sshkey_froms(buf, &k)) != 0 || |
(r = sshkey_from_blob(cert, len, &k)) != 0 || |
|
(r = sshkey_add_private(k)) != 0 || |
(r = sshkey_add_private(k)) != 0 || |
(r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 || |
(r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 || |
(r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0) |
(r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0) |