/* Confirmation hash calculation */ void jpake_confirm_hash(const BIGNUM *k, const u_char *endpoint_id, u_int endpoint_id_len, const u_char *sess_id, u_int sess_id_len, u_char **confirm_hash, u_int *confirm_hash_len) { struct sshbuf *b; int r; /* * Calculate confirmation proof: * client: H(k || client_id || session_id) * server: H(k || server_id || session_id) */ if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_bignum2(b, k)) != 0 || (r = sshbuf_put_string(b, endpoint_id, endpoint_id_len)) != 0 || (r = sshbuf_put_string(b, sess_id, sess_id_len)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (hash_buffer(sshbuf_ptr(b), sshbuf_len(b), EVP_sha256(), confirm_hash, confirm_hash_len) != 0) fatal("%s: hash_buffer", __func__); sshbuf_free(b); }
static void build_cert(struct sshbuf *b, const struct sshkey *k, const char *type, const struct sshkey *sign_key, const struct sshkey *ca_key, const char *sig_alg) { struct sshbuf *ca_buf, *pk, *principals, *critopts, *exts; u_char *sigblob; size_t siglen; ca_buf = sshbuf_new(); ASSERT_PTR_NE(ca_buf, NULL); ASSERT_INT_EQ(sshkey_putb(ca_key, ca_buf), 0); /* * Get the public key serialisation by rendering the key and skipping * the type string. This is a bit of a hack :/ */ pk = sshbuf_new(); ASSERT_PTR_NE(pk, NULL); ASSERT_INT_EQ(sshkey_putb_plain(k, pk), 0); ASSERT_INT_EQ(sshbuf_skip_string(pk), 0); principals = sshbuf_new(); ASSERT_PTR_NE(principals, NULL); ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gsamsa"), 0); ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gregor"), 0); critopts = sshbuf_new(); ASSERT_PTR_NE(critopts, NULL); put_opt(critopts, "force-command", "/usr/local/bin/nethack"); put_opt(critopts, "source-address", "192.168.0.0/24,127.0.0.1,::1"); exts = sshbuf_new(); ASSERT_PTR_NE(exts, NULL); put_opt(critopts, "permit-X11-forwarding", NULL); ASSERT_INT_EQ(sshbuf_put_cstring(b, type), 0); ASSERT_INT_EQ(sshbuf_put_cstring(b, "noncenoncenonce!"), 0); /* nonce */ ASSERT_INT_EQ(sshbuf_putb(b, pk), 0); /* public key serialisation */ ASSERT_INT_EQ(sshbuf_put_u64(b, 1234), 0); /* serial */ ASSERT_INT_EQ(sshbuf_put_u32(b, SSH2_CERT_TYPE_USER), 0); /* type */ ASSERT_INT_EQ(sshbuf_put_cstring(b, "gregor"), 0); /* key ID */ ASSERT_INT_EQ(sshbuf_put_stringb(b, principals), 0); /* principals */ ASSERT_INT_EQ(sshbuf_put_u64(b, 0), 0); /* start */ ASSERT_INT_EQ(sshbuf_put_u64(b, 0xffffffffffffffffULL), 0); /* end */ ASSERT_INT_EQ(sshbuf_put_stringb(b, critopts), 0); /* options */ ASSERT_INT_EQ(sshbuf_put_stringb(b, exts), 0); /* extensions */ ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */ ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */ ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen, sshbuf_ptr(b), sshbuf_len(b), sig_alg, 0), 0); ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ free(sigblob); sshbuf_free(ca_buf); sshbuf_free(exts); sshbuf_free(critopts); sshbuf_free(principals); sshbuf_free(pk); }
static void build_cert(struct sshbuf *b, const struct sshkey *k, const char *type, const struct sshkey *sign_key, const struct sshkey *ca_key) { struct sshbuf *ca_buf, *pk, *principals, *critopts, *exts; u_char *sigblob; size_t siglen; ca_buf = sshbuf_new(); ASSERT_INT_EQ(sshkey_to_blob_buf(ca_key, ca_buf), 0); /* * Get the public key serialisation by rendering the key and skipping * the type string. This is a bit of a hack :/ */ pk = sshbuf_new(); ASSERT_INT_EQ(sshkey_plain_to_blob_buf(k, pk), 0); ASSERT_INT_EQ(sshbuf_skip_string(pk), 0); principals = sshbuf_new(); ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gsamsa"), 0); ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gregor"), 0); critopts = sshbuf_new(); /* XXX fill this in */ exts = sshbuf_new(); /* XXX fill this in */ ASSERT_INT_EQ(sshbuf_put_cstring(b, type), 0); ASSERT_INT_EQ(sshbuf_put_cstring(b, "noncenoncenonce!"), 0); /* nonce */ ASSERT_INT_EQ(sshbuf_putb(b, pk), 0); /* public key serialisation */ ASSERT_INT_EQ(sshbuf_put_u64(b, 1234), 0); /* serial */ ASSERT_INT_EQ(sshbuf_put_u32(b, SSH2_CERT_TYPE_USER), 0); /* type */ ASSERT_INT_EQ(sshbuf_put_cstring(b, "gregor"), 0); /* key ID */ ASSERT_INT_EQ(sshbuf_put_stringb(b, principals), 0); /* principals */ ASSERT_INT_EQ(sshbuf_put_u64(b, 0), 0); /* start */ ASSERT_INT_EQ(sshbuf_put_u64(b, 0xffffffffffffffffULL), 0); /* end */ ASSERT_INT_EQ(sshbuf_put_stringb(b, critopts), 0); /* options */ ASSERT_INT_EQ(sshbuf_put_stringb(b, exts), 0); /* extensions */ ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */ ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */ ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen, sshbuf_ptr(b), sshbuf_len(b), 0), 0); ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ free(sigblob); sshbuf_free(ca_buf); sshbuf_free(exts); sshbuf_free(critopts); sshbuf_free(principals); sshbuf_free(pk); }
/* ask agent to sign data, returns err.h code on error, 0 on success */ int ssh_agent_sign(int sock, struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat) { struct sshbuf *msg; u_char *blob = NULL, type; size_t blen = 0, len = 0; u_int flags = 0; int r = SSH_ERR_INTERNAL_ERROR; if (sigp != NULL) *sigp = NULL; if (lenp != NULL) *lenp = 0; if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) return SSH_ERR_INVALID_ARGUMENT; if (compat & SSH_BUG_SIGBLOB) flags |= SSH_AGENT_OLD_SIGNATURE; if ((msg = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) goto out; if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || (r = sshbuf_put_string(msg, blob, blen)) != 0 || (r = sshbuf_put_string(msg, data, datalen)) != 0 || (r = sshbuf_put_u32(msg, flags)) != 0) goto out; if ((r = ssh_request_reply(sock, msg, msg) != 0)) goto out; if ((r = sshbuf_get_u8(msg, &type)) != 0) goto out; if (agent_failed(type)) { r = SSH_ERR_AGENT_FAILURE; goto out; } else if (type != SSH2_AGENT_SIGN_RESPONSE) { r = SSH_ERR_INVALID_FORMAT; goto out; } if ((r = sshbuf_get_string(msg, sigp, &len)) != 0) goto out; *lenp = len; r = 0; out: if (blob != NULL) { explicit_bzero(blob, blen); free(blob); } sshbuf_free(msg); return r; }
int kex_c25519_hash( int hash_alg, const char *client_version_string, const char *server_version_string, const char *ckexinit, size_t ckexinitlen, const char *skexinit, size_t skexinitlen, const u_char *serverhostkeyblob, size_t sbloblen, const u_char client_dh_pub[CURVE25519_SIZE], const u_char server_dh_pub[CURVE25519_SIZE], const u_char *shared_secret, size_t secretlen, u_char *hash, size_t *hashlen) { struct sshbuf *b; int r; if (*hashlen < ssh_digest_bytes(hash_alg)) return SSH_ERR_INVALID_ARGUMENT; if ((b = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_put_cstring(b, client_version_string)) < 0 || (r = sshbuf_put_cstring(b, server_version_string)) < 0 || /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ (r = sshbuf_put_u32(b, ckexinitlen+1)) < 0 || (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) < 0 || (r = sshbuf_put(b, ckexinit, ckexinitlen)) < 0 || (r = sshbuf_put_u32(b, skexinitlen+1)) < 0 || (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) < 0 || (r = sshbuf_put(b, skexinit, skexinitlen)) < 0 || (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) < 0 || (r = sshbuf_put_string(b, client_dh_pub, CURVE25519_SIZE)) < 0 || (r = sshbuf_put_string(b, server_dh_pub, CURVE25519_SIZE)) < 0 || (r = sshbuf_put(b, shared_secret, secretlen)) < 0) { sshbuf_free(b); return r; } #ifdef DEBUG_KEX sshbuf_dump(b, stderr); #endif if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) { sshbuf_free(b); return SSH_ERR_LIBCRYPTO_ERROR; } sshbuf_free(b); *hashlen = ssh_digest_bytes(hash_alg); #ifdef DEBUG_KEX dump_digest("hash", hash, *hashlen); #endif return 0; }
int sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g) { u_char d[SSHBUF_MAX_ECPOINT]; BN_CTX *bn_ctx; size_t len; int ret; if ((bn_ctx = BN_CTX_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, bn_ctx)) > SSHBUF_MAX_ECPOINT) { BN_CTX_free(bn_ctx); return SSH_ERR_INVALID_ARGUMENT; } if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED, d, len, bn_ctx) != len) { BN_CTX_free(bn_ctx); return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */ } BN_CTX_free(bn_ctx); ret = sshbuf_put_string(buf, d, len); bzero(d, len); return ret; }
int mm_answer_gss_accept_ctx(int sock, struct sshbuf *m) { gss_buffer_desc in; gss_buffer_desc out = GSS_C_EMPTY_BUFFER; OM_uint32 major, minor; OM_uint32 flags = 0; /* GSI needs this */ size_t len; u_char *p; int r; if ((r = sshbuf_get_string(m, &p, &len)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); in.value = p; in.length = len; major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); free(in.value); sshbuf_reset(m); if ((r = sshbuf_put_u32(m, major)) != 0 || (r = sshbuf_put_string(m, out.value, out.length)) != 0 || (r = sshbuf_put_u32(m, flags)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); mm_request_send(sock, MONITOR_ANS_GSSSTEP, m); gss_release_buffer(&minor, &out); if (major == GSS_S_COMPLETE) { monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); } return 0; }
int kexgex_hash( int hash_alg, const char *client_version_string, const char *server_version_string, const u_char *ckexinit, size_t ckexinitlen, const u_char *skexinit, size_t skexinitlen, const u_char *serverhostkeyblob, size_t sbloblen, int min, int wantbits, int max, const BIGNUM *prime, const BIGNUM *gen, const BIGNUM *client_dh_pub, const BIGNUM *server_dh_pub, const BIGNUM *shared_secret, u_char **hash, size_t *hashlen) { struct sshbuf *b; static u_char digest[SSH_DIGEST_MAX_LENGTH]; int r; if ((b = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 || (r = sshbuf_put_cstring(b, server_version_string)) != 0 || /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ (r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 || (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 || (r = sshbuf_put_u32(b, skexinitlen+1)) != 0 || (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 || (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 || (min != -1 && (r = sshbuf_put_u32(b, min)) != 0) || (r = sshbuf_put_u32(b, wantbits)) != 0 || (max != -1 && (r = sshbuf_put_u32(b, max)) != 0) || (r = sshbuf_put_bignum2(b, prime)) != 0 || (r = sshbuf_put_bignum2(b, gen)) != 0 || (r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 || (r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 || (r = sshbuf_put_bignum2(b, shared_secret)) != 0) { sshbuf_free(b); return r; } #ifdef DEBUG_KEXDH sshbuf_dump(b, stderr); #endif if (ssh_digest_buffer(hash_alg, b, digest, sizeof(digest)) != 0) { sshbuf_free(b); return SSH_ERR_LIBCRYPTO_ERROR; } sshbuf_free(b); *hash = digest; *hashlen = ssh_digest_bytes(hash_alg); #ifdef DEBUG_KEXDH dump_digest("hash", digest, *hashlen); #endif return 0; }
void buffer_put_string(Buffer *buffer, const void *buf, u_int len) { int ret; if ((ret = sshbuf_put_string(buffer, buf, len)) != 0) fatal("%s: %s", __func__, ssh_err(ret)); }
int ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat) { u_char *sig = NULL; size_t slen = 0, len; unsigned long long smlen; int r, ret; struct sshbuf *b = NULL; if (lenp != NULL) *lenp = 0; if (sigp != NULL) *sigp = NULL; if (key == NULL || sshkey_type_plain(key->type) != KEY_ED25519 || key->ed25519_sk == NULL || datalen >= INT_MAX - crypto_sign_ed25519_BYTES) return SSH_ERR_INVALID_ARGUMENT; smlen = slen = datalen + crypto_sign_ed25519_BYTES; if ((sig = malloc(slen)) == NULL) return SSH_ERR_ALLOC_FAIL; if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen, key->ed25519_sk)) != 0 || smlen <= datalen) { r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */ goto out; } /* encode signature */ if ((b = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshbuf_put_cstring(b, "ssh-ed25519")) != 0 || (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0) goto out; len = sshbuf_len(b); if (sigp != NULL) { if ((*sigp = malloc(len)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(*sigp, sshbuf_ptr(b), len); } if (lenp != NULL) *lenp = len; /* success */ r = 0; out: sshbuf_free(b); if (sig != NULL) { explicit_bzero(sig, slen); free(sig); } return r; }
int kex_ecdh_hash( const EVP_MD *evp_md, const EC_GROUP *ec_group, const char *client_version_string, const char *server_version_string, const u_char *ckexinit, size_t ckexinitlen, const u_char *skexinit, size_t skexinitlen, const u_char *serverhostkeyblob, size_t sbloblen, const EC_POINT *client_dh_pub, const EC_POINT *server_dh_pub, const BIGNUM *shared_secret, u_char **hash, size_t *hashlen) { struct sshbuf *b; EVP_MD_CTX md; static u_char digest[EVP_MAX_MD_SIZE]; int r; if ((b = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 || (r = sshbuf_put_cstring(b, server_version_string)) != 0 || /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ (r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 || (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 || (r = sshbuf_put_u32(b, skexinitlen+1)) != 0 || (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 || (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 || (r = sshbuf_put_ec(b, client_dh_pub, ec_group)) != 0 || (r = sshbuf_put_ec(b, server_dh_pub, ec_group)) != 0 || (r = sshbuf_put_bignum2(b, shared_secret)) != 0) { sshbuf_free(b); return r; } #ifdef DEBUG_KEX sshbuf_dump(b, stderr); #endif if (EVP_DigestInit(&md, evp_md) != 1 || EVP_DigestUpdate(&md, sshbuf_ptr(b), sshbuf_len(b)) != 1 || EVP_DigestFinal(&md, digest, NULL) != 1) { sshbuf_free(b); return SSH_ERR_LIBCRYPTO_ERROR; } sshbuf_free(b); #ifdef DEBUG_KEX dump_digest("hash", digest, EVP_MD_size(evp_md)); #endif *hash = digest; *hashlen = EVP_MD_size(evp_md); return 0; }
static int pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding) { struct sshkey key; u_char *blob, *signature = NULL; size_t blen, slen = 0; int r, ret = -1; struct sshbuf *msg; if (padding != RSA_PKCS1_PADDING) return (-1); key.type = KEY_RSA; key.rsa = rsa; if ((r = sshkey_to_blob(&key, &blob, &blen)) != 0) { error("%s: sshkey_to_blob: %s", __func__, ssh_err(r)); return -1; } if ((msg = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || (r = sshbuf_put_string(msg, blob, blen)) != 0 || (r = sshbuf_put_string(msg, from, flen)) != 0 || (r = sshbuf_put_u32(msg, 0)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); xfree(blob); send_msg(msg); sshbuf_reset(msg); if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) { if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (slen <= (size_t)RSA_size(rsa)) { memcpy(to, signature, slen); ret = slen; } xfree(signature); } sshbuf_free(msg); return (ret); }
void ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, const char *context) { int r; sshbuf_reset(b); if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 || (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || (r = sshbuf_put_cstring(b, user)) != 0 || (r = sshbuf_put_cstring(b, service)) != 0 || (r = sshbuf_put_cstring(b, context)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); }
int mm_answer_rsa_keyallowed(int sock, struct sshbuf *m) { BIGNUM *client_n; struct sshkey *key = NULL; u_char *blob = NULL; size_t blen = 0; int r, allowed = 0; debug3("%s entering", __func__); auth_method = "rsa"; if (options.rsa_authentication && authctxt->valid) { if ((client_n = BN_new()) == NULL) fatal("%s: BN_new", __func__); if ((r = sshbuf_get_bignum2(m, client_n)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); allowed = auth_rsa_key_allowed(authctxt->pw, client_n, &key); BN_clear_free(client_n); } sshbuf_reset(m); if ((r = sshbuf_put_u32(m, allowed)) != 0 || (r = sshbuf_put_u32(m, forced_command != NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); /* clear temporarily storage (used by generate challenge) */ monitor_reset_key_state(); if (allowed && key != NULL) { key->type = KEY_RSA; /* cheat for key_to_blob */ if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) fatal("%s: key_to_blob failed: %s", __func__, ssh_err(r)); if ((r = sshbuf_put_string(m, blob, blen)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); /* Save temporarily for comparison in verify */ key_blob = blob; key_bloblen = blen; key_blobtype = MM_RSAUSERKEY; } if (key != NULL) sshkey_free(key); mm_request_send(sock, MONITOR_ANS_RSAKEYALLOWED, m); monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed); monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 0); return (0); }
int sshkey_xmss_serialize_enc_key(const struct sshkey *k, struct sshbuf *b) { struct ssh_xmss_state *state = k->xmss_state; int r; if (state == NULL || state->enc_keyiv == NULL || state->enc_ciphername == NULL) return SSH_ERR_INVALID_ARGUMENT; if ((r = sshbuf_put_cstring(b, state->enc_ciphername)) != 0 || (r = sshbuf_put_string(b, state->enc_keyiv, state->enc_keyiv_len)) != 0) return r; return 0; }
static void send_data_or_handle(char type, u_int32_t id, const u_char *data, int dlen) { struct sshbuf *msg; int r; if ((msg = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_u8(msg, type)) != 0 || (r = sshbuf_put_u32(msg, id)) != 0 || (r = sshbuf_put_string(msg, data, dlen)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); send_msg(msg); sshbuf_free(msg); }
/* * Removes an identity from the authentication server. * This call is intended only for use by ssh-add(1) and like applications. */ int ssh_remove_identity(int sock, struct sshkey *key) { struct sshbuf *msg; int r; u_char type, *blob = NULL; size_t blen; if ((msg = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; #ifdef WITH_SSH1 if (key->type == KEY_RSA1) { if ((r = sshbuf_put_u8(msg, SSH_AGENTC_REMOVE_RSA_IDENTITY)) != 0 || (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 || (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 || (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0) goto out; } else #endif if (key->type != KEY_UNSPEC) { if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) goto out; if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_REMOVE_IDENTITY)) != 0 || (r = sshbuf_put_string(msg, blob, blen)) != 0) goto out; } else { r = SSH_ERR_INVALID_ARGUMENT; goto out; } if ((r = ssh_request_reply(sock, msg, msg)) != 0) goto out; if ((r = sshbuf_get_u8(msg, &type)) != 0) goto out; r = decode_reply(type); out: if (blob != NULL) { explicit_bzero(blob, blen); free(blob); } sshbuf_free(msg); return r; }
int sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v) { u_char d[SSHBUF_MAX_BIGNUM + 1]; int len = BN_num_bytes(v), prepend = 0, r; if (len < 0 || len > SSHBUF_MAX_BIGNUM) return SSH_ERR_INVALID_ARGUMENT; *d = '\0'; if (BN_bn2bin(v, d + 1) != len) return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */ /* If MSB is set, prepend a \0 */ if (len > 0 && (d[1] & 0x80) != 0) prepend = 1; if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) { bzero(d, sizeof(d)); return r; } bzero(d, sizeof(d)); return 0; }
int sshkey_xmss_serialize_state(const struct sshkey *k, struct sshbuf *b) { struct ssh_xmss_state *state = k->xmss_state; treehash_inst *th; u_int32_t i, node; int r; if (state == NULL) return SSH_ERR_INVALID_ARGUMENT; if (state->stack == NULL) return SSH_ERR_INVALID_ARGUMENT; state->stackoffset = state->bds.stackoffset; /* copy back */ if ((r = sshbuf_put_cstring(b, SSH_XMSS_K2_MAGIC)) != 0 || (r = sshbuf_put_u32(b, state->idx)) != 0 || (r = sshbuf_put_string(b, state->stack, num_stack(state))) != 0 || (r = sshbuf_put_u32(b, state->stackoffset)) != 0 || (r = sshbuf_put_string(b, state->stacklevels, num_stacklevels(state))) != 0 || (r = sshbuf_put_string(b, state->auth, num_auth(state))) != 0 || (r = sshbuf_put_string(b, state->keep, num_keep(state))) != 0 || (r = sshbuf_put_string(b, state->th_nodes, num_th_nodes(state))) != 0 || (r = sshbuf_put_string(b, state->retain, num_retain(state))) != 0 || (r = sshbuf_put_u32(b, num_treehash(state))) != 0) return r; for (i = 0; i < num_treehash(state); i++) { th = &state->treehash[i]; node = th->node - state->th_nodes; if ((r = sshbuf_put_u32(b, th->h)) != 0 || (r = sshbuf_put_u32(b, th->next_idx)) != 0 || (r = sshbuf_put_u32(b, th->stackusage)) != 0 || (r = sshbuf_put_u8(b, th->completed)) != 0 || (r = sshbuf_put_u32(b, node)) != 0) return r; } return 0; }
static int server_input_hostkeys_prove(struct sshbuf **respp) { struct ssh *ssh = active_state; /* XXX */ struct sshbuf *resp = NULL; struct sshbuf *sigbuf = NULL; struct sshkey *key = NULL, *key_pub = NULL, *key_prv = NULL; int r, ndx, success = 0; const u_char *blob; u_char *sig = 0; size_t blen, slen; if ((resp = sshbuf_new()) == NULL || (sigbuf = sshbuf_new()) == NULL) fatal("%s: sshbuf_new", __func__); while (ssh_packet_remaining(ssh) > 0) { sshkey_free(key); key = NULL; if ((r = sshpkt_get_string_direct(ssh, &blob, &blen)) != 0 || (r = sshkey_from_blob(blob, blen, &key)) != 0) { error("%s: couldn't parse key: %s", __func__, ssh_err(r)); goto out; } /* * Better check that this is actually one of our hostkeys * before attempting to sign anything with it. */ if ((ndx = ssh->kex->host_key_index(key, 1, ssh)) == -1) { error("%s: unknown host %s key", __func__, sshkey_type(key)); goto out; } /* * XXX refactor: make kex->sign just use an index rather * than passing in public and private keys */ if ((key_prv = get_hostkey_by_index(ndx)) == NULL && (key_pub = get_hostkey_public_by_index(ndx, ssh)) == NULL) { error("%s: can't retrieve hostkey %d", __func__, ndx); goto out; } sshbuf_reset(sigbuf); free(sig); sig = NULL; if ((r = sshbuf_put_cstring(sigbuf, "*****@*****.**")) != 0 || (r = sshbuf_put_string(sigbuf, ssh->kex->session_id, ssh->kex->session_id_len)) != 0 || (r = sshkey_puts(key, sigbuf)) != 0 || (r = ssh->kex->sign(key_prv, key_pub, &sig, &slen, sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), 0)) != 0 || (r = sshbuf_put_string(resp, sig, slen)) != 0) { error("%s: couldn't prepare signature: %s", __func__, ssh_err(r)); goto out; } } /* Success */ *respp = resp; resp = NULL; /* don't free it */ success = 1; out: free(sig); sshbuf_free(resp); sshbuf_free(sigbuf); sshkey_free(key); return success; }
int main(int argc, char **argv) { struct sshbuf *b; Options options; #define NUM_KEYTYPES 4 struct sshkey *keys[NUM_KEYTYPES], *key = NULL; struct passwd *pw; int r, key_fd[NUM_KEYTYPES], i, found, version = 2, fd; u_char *signature, *data, rver; char *host, *fp; size_t slen, dlen; #ifdef WITH_OPENSSL u_int32_t rnd[256]; #endif if (pledge("stdio rpath getpw dns id", NULL) != 0) fatal("%s: pledge: %s", __progname, strerror(errno)); /* Ensure that stdin and stdout are connected */ if ((fd = open(_PATH_DEVNULL, O_RDWR)) < 2) exit(1); /* Leave /dev/null fd iff it is attached to stderr */ if (fd > 2) close(fd); i = 0; /* XXX This really needs to read sshd_config for the paths */ key_fd[i++] = open(_PATH_HOST_DSA_KEY_FILE, O_RDONLY); key_fd[i++] = open(_PATH_HOST_ECDSA_KEY_FILE, O_RDONLY); key_fd[i++] = open(_PATH_HOST_ED25519_KEY_FILE, O_RDONLY); key_fd[i++] = open(_PATH_HOST_RSA_KEY_FILE, O_RDONLY); original_real_uid = getuid(); /* XXX readconf.c needs this */ if ((pw = getpwuid(original_real_uid)) == NULL) fatal("getpwuid failed"); pw = pwcopy(pw); permanently_set_uid(pw); seed_rng(); #ifdef DEBUG_SSH_KEYSIGN log_init("ssh-keysign", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0); #endif /* verify that ssh-keysign is enabled by the admin */ initialize_options(&options); (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", "", &options, 0); fill_default_options(&options); if (options.enable_ssh_keysign != 1) fatal("ssh-keysign not enabled in %s", _PATH_HOST_CONFIG_FILE); for (i = found = 0; i < NUM_KEYTYPES; i++) { if (key_fd[i] != -1) found = 1; } if (found == 0) fatal("could not open any host key"); #ifdef WITH_OPENSSL OpenSSL_add_all_algorithms(); arc4random_buf(rnd, sizeof(rnd)); RAND_seed(rnd, sizeof(rnd)); #endif found = 0; for (i = 0; i < NUM_KEYTYPES; i++) { keys[i] = NULL; if (key_fd[i] == -1) continue; r = sshkey_load_private_type_fd(key_fd[i], KEY_UNSPEC, NULL, &key, NULL); close(key_fd[i]); if (r != 0) debug("parse key %d: %s", i, ssh_err(r)); else if (key != NULL) { keys[i] = key; found = 1; } } if (!found) fatal("no hostkey found"); if (pledge("stdio dns", NULL) != 0) fatal("%s: pledge: %s", __progname, strerror(errno)); if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __progname); if (ssh_msg_recv(STDIN_FILENO, b) < 0) fatal("ssh_msg_recv failed"); if ((r = sshbuf_get_u8(b, &rver)) != 0) fatal("%s: buffer error: %s", __progname, ssh_err(r)); if (rver != version) fatal("bad version: received %d, expected %d", rver, version); if ((r = sshbuf_get_u32(b, (u_int *)&fd)) != 0) fatal("%s: buffer error: %s", __progname, ssh_err(r)); if (fd < 0 || fd == STDIN_FILENO || fd == STDOUT_FILENO) fatal("bad fd"); if ((host = get_local_name(fd)) == NULL) fatal("cannot get local name for fd"); if ((r = sshbuf_get_string(b, &data, &dlen)) != 0) fatal("%s: buffer error: %s", __progname, ssh_err(r)); if (valid_request(pw, host, &key, data, dlen) < 0) fatal("not a valid request"); free(host); found = 0; for (i = 0; i < NUM_KEYTYPES; i++) { if (keys[i] != NULL && sshkey_equal_public(key, keys[i])) { found = 1; break; } } if (!found) { if ((fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) fatal("%s: sshkey_fingerprint failed", __progname); fatal("no matching hostkey found for key %s %s", sshkey_type(key), fp ? fp : ""); } if ((r = sshkey_sign(keys[i], &signature, &slen, data, dlen, NULL, 0)) != 0) fatal("sshkey_sign failed: %s", ssh_err(r)); free(data); /* send reply */ sshbuf_reset(b); if ((r = sshbuf_put_string(b, signature, slen)) != 0) fatal("%s: buffer error: %s", __progname, ssh_err(r)); if (ssh_msg_send(STDOUT_FILENO, version, b) == -1) fatal("ssh_msg_send failed"); return (0); }
int sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v) { return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v)); }
int sshbuf_put_cstring(struct sshbuf *buf, const char *v) { return sshbuf_put_string(buf, (u_char *)v, strlen(v)); }
int ssh_dss_sign(const struct sshkey *key, u_char **sigp, u_int *lenp, const u_char *data, u_int datalen, u_int compat) { DSA_SIG *sig = NULL; const EVP_MD *evp_md = EVP_sha1(); EVP_MD_CTX md; u_char digest[EVP_MAX_MD_SIZE], sigblob[SIGBLOB_LEN]; u_int rlen, slen, len, dlen; struct sshbuf *b = NULL; int ret = SSH_ERR_INVALID_ARGUMENT; if (key == NULL || key->dsa == NULL || (key->type != KEY_DSA && key->type != KEY_DSA_CERT && key->type != KEY_DSA_CERT_V00)) return SSH_ERR_INVALID_ARGUMENT; if (EVP_DigestInit(&md, evp_md) != 1 || EVP_DigestUpdate(&md, data, datalen) != 1 || EVP_DigestFinal(&md, digest, &dlen) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } rlen = BN_num_bytes(sig->r); slen = BN_num_bytes(sig->s); if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { ret = SSH_ERR_INTERNAL_ERROR; goto out; } bzero(sigblob, SIGBLOB_LEN); BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen); if (compat & SSH_BUG_SIGBLOB) { if (lenp != NULL) *lenp = SIGBLOB_LEN; if (sigp != NULL) { if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(*sigp, sigblob, SIGBLOB_LEN); } ret = 0; } else { /* ietf-drafts */ if ((b = sshbuf_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 || (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0) goto out; len = sshbuf_len(b); if (lenp != NULL) *lenp = len; if (sigp != NULL) { if ((*sigp = malloc(len)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(*sigp, sshbuf_ptr(b), len); } ret = 0; } out: bzero(&md, sizeof(md)); bzero(digest, sizeof(digest)); if (sig != NULL) DSA_SIG_free(sig); if (b != NULL) sshbuf_free(b); return ret; }
int ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat) { DSA_SIG *sig = NULL; u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); struct sshbuf *b = NULL; int ret = SSH_ERR_INVALID_ARGUMENT; if (lenp != NULL) *lenp = 0; if (sigp != NULL) *sigp = NULL; if (key == NULL || key->dsa == NULL || sshkey_type_plain(key->type) != KEY_DSA) return SSH_ERR_INVALID_ARGUMENT; if (dlen == 0) return SSH_ERR_INTERNAL_ERROR; if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, digest, sizeof(digest))) != 0) goto out; if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } rlen = BN_num_bytes(sig->r); slen = BN_num_bytes(sig->s); if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { ret = SSH_ERR_INTERNAL_ERROR; goto out; } explicit_bzero(sigblob, SIGBLOB_LEN); BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen); if (compat & SSH_BUG_SIGBLOB) { if (sigp != NULL) { if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(*sigp, sigblob, SIGBLOB_LEN); } if (lenp != NULL) *lenp = SIGBLOB_LEN; ret = 0; } else { /* ietf-drafts */ if ((b = sshbuf_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 || (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0) goto out; len = sshbuf_len(b); if (sigp != NULL) { if ((*sigp = malloc(len)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(*sigp, sshbuf_ptr(b), len); } if (lenp != NULL) *lenp = len; ret = 0; } out: explicit_bzero(digest, sizeof(digest)); if (sig != NULL) DSA_SIG_free(sig); sshbuf_free(b); return ret; }
static int userauth_hostbased(struct ssh *ssh) { Authctxt *authctxt = ssh->authctxt; struct sshbuf *b; struct sshkey *key = NULL; char *pkalg, *cuser, *chost; u_char *pkblob, *sig; size_t alen, blen, slen; int r, pktype, authenticated = 0; if (!authctxt->valid) { debug2("%s: disabled because of invalid user", __func__); return 0; } /* XXX use sshkey_froms() */ if ((r = sshpkt_get_cstring(ssh, &pkalg, &alen)) != 0 || (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 || (r = sshpkt_get_cstring(ssh, &chost, NULL)) != 0 || (r = sshpkt_get_cstring(ssh, &cuser, NULL)) != 0 || (r = sshpkt_get_string(ssh, &sig, &slen)) != 0) fatal("%s: packet parsing: %s", __func__, ssh_err(r)); debug("%s: cuser %s chost %s pkalg %s slen %zu", __func__, cuser, chost, pkalg, slen); #ifdef DEBUG_PK debug("signature:"); sshbuf_dump_data(sig, siglen, stderr); #endif pktype = sshkey_type_from_name(pkalg); if (pktype == KEY_UNSPEC) { /* this is perfectly legal */ logit("%s: unsupported public key algorithm: %s", __func__, pkalg); goto done; } if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) { error("%s: key_from_blob: %s", __func__, ssh_err(r)); goto done; } if (key == NULL) { error("%s: cannot decode key: %s", __func__, pkalg); goto done; } if (key->type != pktype) { error("%s: type mismatch for decoded key " "(received %d, expected %d)", __func__, key->type, pktype); goto done; } if (sshkey_type_plain(key->type) == KEY_RSA && (ssh->compat & SSH_BUG_RSASIGMD5) != 0) { error("Refusing RSA key because peer uses unsafe " "signature format"); goto done; } if (match_pattern_list(sshkey_ssh_name(key), options.hostbased_key_types, 0) != 1) { logit("%s: key type %s not in HostbasedAcceptedKeyTypes", __func__, sshkey_type(key)); goto done; } if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); /* reconstruct packet */ if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 || (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || (r = sshbuf_put_cstring(b, authctxt->user)) != 0 || (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || (r = sshbuf_put_cstring(b, "hostbased")) != 0 || (r = sshbuf_put_string(b, pkalg, alen)) != 0 || (r = sshbuf_put_string(b, pkblob, blen)) != 0 || (r = sshbuf_put_cstring(b, chost)) != 0 || (r = sshbuf_put_cstring(b, cuser)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); #ifdef DEBUG_PK sshbuf_dump(b, stderr); #endif auth2_record_info(authctxt, "client user \"%.100s\", client host \"%.100s\"", cuser, chost); /* test for allowed key and correct signature */ authenticated = 0; if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), pkalg, ssh->compat)) == 0) authenticated = 1; auth2_record_key(authctxt, authenticated, key); sshbuf_free(b); done: debug2("%s: authenticated %d", __func__, authenticated); sshkey_free(key); free(pkalg); free(pkblob); free(cuser); free(chost); free(sig); return authenticated; }
/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ int ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, const char *alg_ident) { u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; size_t slen; u_int dlen, len; int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; struct sshbuf *b = NULL; if (lenp != NULL) *lenp = 0; if (sigp != NULL) *sigp = NULL; if (alg_ident == NULL || strlen(alg_ident) == 0 || strncmp(alg_ident, "ssh-rsa-cert", strlen("ssh-rsa-cert")) == 0) hash_alg = SSH_DIGEST_SHA1; else hash_alg = rsa_hash_alg_from_ident(alg_ident); if (key == NULL || key->rsa == NULL || hash_alg == -1 || sshkey_type_plain(key->type) != KEY_RSA || BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) return SSH_ERR_INVALID_ARGUMENT; slen = RSA_size(key->rsa); if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) return SSH_ERR_INVALID_ARGUMENT; /* hash the data */ nid = rsa_hash_alg_nid(hash_alg); if ((dlen = ssh_digest_bytes(hash_alg)) == 0) return SSH_ERR_INTERNAL_ERROR; if ((ret = ssh_digest_memory(hash_alg, data, datalen, digest, sizeof(digest))) != 0) goto out; if ((sig = malloc(slen)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if (len < slen) { size_t diff = slen - len; memmove(sig + diff, sig, len); explicit_bzero(sig, diff); } else if (len > slen) { ret = SSH_ERR_INTERNAL_ERROR; goto out; } /* encode signature */ if ((b = sshbuf_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 || (ret = sshbuf_put_string(b, sig, slen)) != 0) goto out; len = sshbuf_len(b); if (sigp != NULL) { if ((*sigp = malloc(len)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(*sigp, sshbuf_ptr(b), len); } if (lenp != NULL) *lenp = len; ret = 0; out: explicit_bzero(digest, sizeof(digest)); if (sig != NULL) { explicit_bzero(sig, slen); free(sig); } sshbuf_free(b); return ret; }
void sshbuf_getput_crypto_tests(void) { struct sshbuf *p1; const u_char *d; size_t s; BIGNUM *bn, *bn2, *bn_x, *bn_y; /* This one has num_bits != num_bytes * 8 to test bignum1 encoding */ const char *hexbn1 = "0102030405060708090a0b0c0d0e0f10"; /* This one has MSB set to test bignum2 encoding negative-avoidance */ const char *hexbn2 = "f0e0d0c0b0a0908070605040302010007fff11"; u_char expbn1[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, }; u_char expbn2[] = { 0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00, 0x7f, 0xff, 0x11 }; int ec256_nid = NID_X9_62_prime256v1; char *ec256_x = "0C828004839D0106AA59575216191357" "34B451459DADB586677EF9DF55784999"; char *ec256_y = "4D196B50F0B4E94B3C73E3A9D4CD9DF2" "C8F9A35E42BDD047550F69D80EC23CD4"; u_char expec256[] = { 0x04, 0x0c, 0x82, 0x80, 0x04, 0x83, 0x9d, 0x01, 0x06, 0xaa, 0x59, 0x57, 0x52, 0x16, 0x19, 0x13, 0x57, 0x34, 0xb4, 0x51, 0x45, 0x9d, 0xad, 0xb5, 0x86, 0x67, 0x7e, 0xf9, 0xdf, 0x55, 0x78, 0x49, 0x99, 0x4d, 0x19, 0x6b, 0x50, 0xf0, 0xb4, 0xe9, 0x4b, 0x3c, 0x73, 0xe3, 0xa9, 0xd4, 0xcd, 0x9d, 0xf2, 0xc8, 0xf9, 0xa3, 0x5e, 0x42, 0xbd, 0xd0, 0x47, 0x55, 0x0f, 0x69, 0xd8, 0x0e, 0xc2, 0x3c, 0xd4 }; EC_KEY *eck; EC_POINT *ecp; int r; #define MKBN(b, bnn) \ do { \ bnn = NULL; \ ASSERT_INT_GT(BN_hex2bn(&bnn, b), 0); \ } while (0) TEST_START("sshbuf_put_bignum1"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_bignum1(p1, bn), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 2); ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), (u_int16_t)BN_num_bits(bn)); ASSERT_MEM_EQ(sshbuf_ptr(p1) + 2, expbn1, sizeof(expbn1)); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum1 limited"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 1), 0); r = sshbuf_put_bignum1(p1, bn); ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum1 bn2"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_bignum1(p1, bn), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 2); ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), (u_int16_t)BN_num_bits(bn)); ASSERT_MEM_EQ(sshbuf_ptr(p1) + 2, expbn2, sizeof(expbn2)); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum1 bn2 limited"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 1), 0); r = sshbuf_put_bignum1(p1, bn); ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum2"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_bignum2(p1, bn), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 4); ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), (u_int32_t)BN_num_bytes(bn)); ASSERT_MEM_EQ(sshbuf_ptr(p1) + 4, expbn1, sizeof(expbn1)); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum2 limited"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 3), 0); r = sshbuf_put_bignum2(p1, bn); ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum2 bn2"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_bignum2(p1, bn), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 4 + 1); /* MSB */ ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), (u_int32_t)BN_num_bytes(bn) + 1); ASSERT_U8_EQ(*(sshbuf_ptr(p1) + 4), 0x00); ASSERT_MEM_EQ(sshbuf_ptr(p1) + 5, expbn2, sizeof(expbn2)); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum2 bn2 limited"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn2) + 3), 0); r = sshbuf_put_bignum2(p1, bn); ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum1"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1)), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1)); ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0); bn2 = BN_new(); ASSERT_INT_EQ(sshbuf_get_bignum1(p1, bn2), 0); ASSERT_BIGNUM_EQ(bn, bn2); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum1 truncated"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1) - 1), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1) - 1); bn2 = BN_new(); r = sshbuf_get_bignum1(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1) - 1); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum1 giant"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xffff), 0); ASSERT_INT_EQ(sshbuf_reserve(p1, (0xffff + 7) / 8, NULL), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + ((0xffff + 7) / 8)); bn2 = BN_new(); r = sshbuf_get_bignum1(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_TOO_LARGE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + ((0xffff + 7) / 8)); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum1 bn2"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2)); ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0); bn2 = BN_new(); ASSERT_INT_EQ(sshbuf_get_bignum1(p1, bn2), 0); ASSERT_BIGNUM_EQ(bn, bn2); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum1 bn2 truncated"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2) - 1), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2) - 1); bn2 = BN_new(); r = sshbuf_get_bignum1(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2) - 1); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum2"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1)), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4 + sizeof(expbn1)); ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0); bn2 = BN_new(); ASSERT_INT_EQ(sshbuf_get_bignum2(p1, bn2), 0); ASSERT_BIGNUM_EQ(bn, bn2); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum2 truncated"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1) - 1), 0); bn2 = BN_new(); r = sshbuf_get_bignum2(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 3); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum2 giant"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, 65536), 0); ASSERT_INT_EQ(sshbuf_reserve(p1, 65536, NULL), 0); bn2 = BN_new(); r = sshbuf_get_bignum2(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_TOO_LARGE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 65536 + 4); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum2 bn2"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn) + 1), 0); /* MSB */ ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4 + 1 + sizeof(expbn2)); ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0); bn2 = BN_new(); ASSERT_INT_EQ(sshbuf_get_bignum2(p1, bn2), 0); ASSERT_BIGNUM_EQ(bn, bn2); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum2 bn2 truncated"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn) + 1), 0); ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2) - 1), 0); bn2 = BN_new(); r = sshbuf_get_bignum2(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 1 + 4 - 1); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum2 bn2 negative"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0); bn2 = BN_new(); r = sshbuf_get_bignum2(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_IS_NEGATIVE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 4); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_ec"); eck = EC_KEY_new_by_curve_name(ec256_nid); ASSERT_PTR_NE(eck, NULL); ecp = EC_POINT_new(EC_KEY_get0_group(eck)); ASSERT_PTR_NE(ecp, NULL); MKBN(ec256_x, bn_x); MKBN(ec256_y, bn_y); ASSERT_INT_EQ(EC_POINT_set_affine_coordinates_GFp( EC_KEY_get0_group(eck), ecp, bn_x, bn_y, NULL), 1); ASSERT_INT_EQ(EC_KEY_set_public_key(eck, ecp), 1); EC_POINT_free(ecp); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_eckey(p1, eck), 0); ASSERT_INT_EQ(sshbuf_get_string_direct(p1, &d, &s), 0); ASSERT_SIZE_T_EQ(s, sizeof(expec256)); ASSERT_MEM_EQ(d, expec256, sizeof(expec256)); sshbuf_free(p1); EC_KEY_free(eck); TEST_DONE(); TEST_START("sshbuf_get_ec"); eck = EC_KEY_new_by_curve_name(ec256_nid); ASSERT_PTR_NE(eck, NULL); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_string(p1, expec256, sizeof(expec256)), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expec256) + 4); ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0); ASSERT_INT_EQ(sshbuf_get_eckey(p1, eck), 0); bn_x = BN_new(); bn_y = BN_new(); ASSERT_PTR_NE(bn_x, NULL); ASSERT_PTR_NE(bn_y, NULL); ASSERT_INT_EQ(EC_POINT_get_affine_coordinates_GFp( EC_KEY_get0_group(eck), EC_KEY_get0_public_key(eck), bn_x, bn_y, NULL), 1); MKBN(ec256_x, bn); MKBN(ec256_y, bn2); ASSERT_INT_EQ(BN_cmp(bn_x, bn), 0); ASSERT_INT_EQ(BN_cmp(bn_y, bn2), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1); sshbuf_free(p1); EC_KEY_free(eck); BN_free(bn_x); BN_free(bn_y); BN_free(bn); BN_free(bn2); TEST_DONE(); }
int sshbuf_put_cstring(struct sshbuf *buf, const char *v) { return sshbuf_put_string(buf, __UNCONST(v), v == NULL ? 0 : strlen(v)); }
/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ int ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat) { int hash_alg; u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; size_t slen; u_int dlen, len; int nid, ret = SSH_ERR_INTERNAL_ERROR; struct sshbuf *b = NULL; if (lenp != NULL) *lenp = 0; if (sigp != NULL) *sigp = NULL; if (key == NULL || key->rsa == NULL || sshkey_type_plain(key->type) != KEY_RSA) return SSH_ERR_INVALID_ARGUMENT; slen = RSA_size(key->rsa); if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) return SSH_ERR_INVALID_ARGUMENT; /* hash the data */ hash_alg = SSH_DIGEST_SHA1; nid = NID_sha1; if ((dlen = ssh_digest_bytes(hash_alg)) == 0) return SSH_ERR_INTERNAL_ERROR; if ((ret = ssh_digest_memory(hash_alg, data, datalen, digest, sizeof(digest))) != 0) goto out; if ((sig = malloc(slen)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if (len < slen) { size_t diff = slen - len; memmove(sig + diff, sig, len); explicit_bzero(sig, diff); } else if (len > slen) { ret = SSH_ERR_INTERNAL_ERROR; goto out; } /* encode signature */ if ((b = sshbuf_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if ((ret = sshbuf_put_cstring(b, "ssh-rsa")) != 0 || (ret = sshbuf_put_string(b, sig, slen)) != 0) goto out; len = sshbuf_len(b); if (sigp != NULL) { if ((*sigp = malloc(len)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(*sigp, sshbuf_ptr(b), len); } if (lenp != NULL) *lenp = len; ret = 0; out: explicit_bzero(digest, sizeof(digest)); if (sig != NULL) { explicit_bzero(sig, slen); free(sig); } if (b != NULL) sshbuf_free(b); return ret; }