int ssh_remove_identity(AuthenticationConnection *auth, Key *key) { Buffer msg; int type; u_char *blob; u_int blen; buffer_init(&msg); if (key->type == KEY_RSA1) { buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY); buffer_put_int(&msg, BN_num_bits(key->rsa->n)); buffer_put_bignum(&msg, key->rsa->e); buffer_put_bignum(&msg, key->rsa->n); } else if (key_type_plain(key->type) == KEY_DSA || key_type_plain(key->type) == KEY_RSA || key_type_plain(key->type) == KEY_ECDSA) { key_to_blob(key, &blob, &blen); buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); buffer_put_string(&msg, blob, blen); free(blob); } else { buffer_free(&msg); return 0; } if (ssh_request_reply(auth, &msg, &msg) == 0) { buffer_free(&msg); return 0; } type = buffer_get_char(&msg); buffer_free(&msg); return decode_reply(type); }
int ssh_ecdsa_sign(const Key *key, u_char **sigp, u_int *lenp, const u_char *data, u_int datalen) { ECDSA_SIG *sig; int hash_alg; u_char digest[SSH_DIGEST_MAX_LENGTH]; u_int len, dlen; Buffer b, bb; if (key == NULL || key_type_plain(key->type) != KEY_ECDSA || key->ecdsa == NULL) { error("%s: no ECDSA key", __func__); return -1; } hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid); if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { error("%s: bad hash algorithm %d", __func__, hash_alg); return -1; } if (ssh_digest_memory(hash_alg, data, datalen, digest, sizeof(digest)) != 0) { error("%s: digest_memory failed", __func__); return -1; } sig = ECDSA_do_sign(digest, dlen, key->ecdsa); explicit_bzero(digest, sizeof(digest)); if (sig == NULL) { error("%s: sign failed", __func__); return -1; } buffer_init(&bb); buffer_put_bignum2(&bb, sig->r); buffer_put_bignum2(&bb, sig->s); ECDSA_SIG_free(sig); buffer_init(&b); buffer_put_cstring(&b, key_ssh_name_plain(key)); buffer_put_string(&b, buffer_ptr(&bb), buffer_len(&bb)); buffer_free(&bb); len = buffer_len(&b); if (lenp != NULL) *lenp = len; if (sigp != NULL) { *sigp = xmalloc(len); memcpy(*sigp, buffer_ptr(&b), len); } buffer_free(&b); return 0; }
int ssh_ed25519_sign(const Key *key, u_char **sigp, u_int *lenp, const u_char *data, u_int datalen) { u_char *sig; u_int slen, len; unsigned long long smlen; int ret; Buffer b; if (key == NULL || key_type_plain(key->type) != KEY_ED25519 || key->ed25519_sk == NULL) { error("%s: no ED25519 key", __func__); return -1; } if (datalen >= UINT_MAX - crypto_sign_ed25519_BYTES) { error("%s: datalen %u too long", __func__, datalen); return -1; } smlen = slen = datalen + crypto_sign_ed25519_BYTES; sig = xmalloc(slen); if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen, key->ed25519_sk)) != 0 || smlen <= datalen) { error("%s: crypto_sign_ed25519 failed: %d", __func__, ret); free(sig); return -1; } /* encode signature */ buffer_init(&b); buffer_put_cstring(&b, "ssh-ed25519"); buffer_put_string(&b, sig, smlen - datalen); len = buffer_len(&b); if (lenp != NULL) *lenp = len; if (sigp != NULL) { *sigp = xmalloc(len); memcpy(*sigp, buffer_ptr(&b), len); } buffer_free(&b); explicit_bzero(sig, slen); free(sig); return 0; }
static int userauth_pubkey(Authctxt *authctxt) { Buffer b; Key *key = NULL; char *pkalg, *userstyle; u_char *pkblob, *sig; u_int alen, blen, slen; int have_sig, pktype; int authenticated = 0; if (!authctxt->valid) { debug2("userauth_pubkey: disabled because of invalid user"); return 0; } have_sig = packet_get_char(); if (datafellows & SSH_BUG_PKAUTH) { debug2("userauth_pubkey: SSH_BUG_PKAUTH"); /* no explicit pkalg given */ pkblob = packet_get_string(&blen); buffer_init(&b); buffer_append(&b, pkblob, blen); /* so we have to extract the pkalg from the pkblob */ pkalg = buffer_get_string(&b, &alen); buffer_free(&b); } else { pkalg = packet_get_string(&alen); pkblob = packet_get_string(&blen); } pktype = key_type_from_name(pkalg); if (pktype == KEY_UNSPEC) { /* this is perfectly legal */ logit("userauth_pubkey: unsupported public key algorithm: %s", pkalg); goto done; } key = key_from_blob(pkblob, blen); if (key == NULL) { error("userauth_pubkey: cannot decode key: %s", pkalg); goto done; } if (key->type != pktype) { error("userauth_pubkey: type mismatch for decoded key " "(received %d, expected %d)", key->type, pktype); goto done; } if (key_type_plain(key->type) == KEY_RSA && (datafellows & SSH_BUG_RSASIGMD5) != 0) { logit("Refusing RSA key because client uses unsafe " "signature scheme"); goto done; } if (auth2_userkey_already_used(authctxt, key)) { logit("refusing previously-used %s key", key_type(key)); goto done; } if (match_pattern_list(sshkey_ssh_name(key), options.pubkey_key_types, strlen(options.pubkey_key_types), 0) != 1) { logit("%s: key type %s not in PubkeyAcceptedKeyTypes", __func__, sshkey_ssh_name(key)); goto done; } if (have_sig) { sig = packet_get_string(&slen); packet_check_eom(); buffer_init(&b); if (datafellows & SSH_OLD_SESSIONID) { buffer_append(&b, session_id2, session_id2_len); } else { buffer_put_string(&b, session_id2, session_id2_len); } /* reconstruct packet */ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", authctxt->style ? authctxt->style : ""); buffer_put_cstring(&b, userstyle); free(userstyle); buffer_put_cstring(&b, datafellows & SSH_BUG_PKSERVICE ? "ssh-userauth" : authctxt->service); if (datafellows & SSH_BUG_PKAUTH) { buffer_put_char(&b, have_sig); } else { buffer_put_cstring(&b, "publickey"); buffer_put_char(&b, have_sig); buffer_put_cstring(&b, pkalg); } buffer_put_string(&b, pkblob, blen); #ifdef DEBUG_PK buffer_dump(&b); #endif pubkey_auth_info(authctxt, key, NULL); /* test for correct signature */ authenticated = 0; if (PRIVSEP(user_key_allowed(authctxt->pw, key)) && PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b))) == 1) { authenticated = 1; /* Record the successful key to prevent reuse */ auth2_record_userkey(authctxt, key); key = NULL; /* Don't free below */ } buffer_free(&b); free(sig); } else { debug("test whether pkalg/pkblob are acceptable"); packet_check_eom(); /* XXX fake reply and always send PK_OK ? */ /* * XXX this allows testing whether a user is allowed * to login: if you happen to have a valid pubkey this * message is sent. the message is NEVER sent at all * if a user is not allowed to login. is this an * issue? -markus */ if (PRIVSEP(user_key_allowed(authctxt->pw, key))) { packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); packet_put_string(pkblob, blen); packet_send(); packet_write_wait(); authctxt->postponed = 1; } } if (authenticated != 1) auth_clear_options(); done: debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); if (key != NULL) key_free(key); free(pkalg); free(pkblob); return authenticated; }
static int userauth_pubkey(Authctxt *authctxt) { #ifdef WIN32_FIXME int loginStat = 1; char currentUser[MAX_PATH] = {0}; DWORD currentUserSize = sizeof(currentUser); int targetIsCurrent = 0; # ifdef USE_NTCREATETOKEN int doOpenSSHVerify = 1; # else int doOpenSSHVerify = 0; # endif #endif Buffer b; Key *key = NULL; char *pkalg, *userstyle; u_char *pkblob, *sig; u_int alen, blen, slen; int have_sig, pktype; int authenticated = 0; if (!authctxt->valid) { debug2("userauth_pubkey: disabled because of invalid user"); return 0; } have_sig = packet_get_char(); if (datafellows & SSH_BUG_PKAUTH) { debug2("userauth_pubkey: SSH_BUG_PKAUTH"); /* no explicit pkalg given */ pkblob = packet_get_string(&blen); buffer_init(&b); buffer_append(&b, pkblob, blen); /* so we have to extract the pkalg from the pkblob */ pkalg = buffer_get_string(&b, &alen); buffer_free(&b); } else { pkalg = packet_get_string(&alen); pkblob = packet_get_string(&blen); } pktype = key_type_from_name(pkalg); if (pktype == KEY_UNSPEC) { /* this is perfectly legal */ logit("userauth_pubkey: unsupported public key algorithm: %s", pkalg); goto done; } key = key_from_blob(pkblob, blen); if (key == NULL) { error("userauth_pubkey: cannot decode key: %s", pkalg); goto done; } if (key->type != pktype) { error("userauth_pubkey: type mismatch for decoded key " "(received %d, expected %d)", key->type, pktype); goto done; } if (key_type_plain(key->type) == KEY_RSA && (datafellows & SSH_BUG_RSASIGMD5) != 0) { logit("Refusing RSA key because client uses unsafe " "signature scheme"); goto done; } if (auth2_userkey_already_used(authctxt, key)) { logit("refusing previously-used %s key", key_type(key)); goto done; } if (match_pattern_list(sshkey_ssh_name(key), options.pubkey_key_types, 0) != 1) { logit("%s: key type %s not in PubkeyAcceptedKeyTypes", __func__, sshkey_ssh_name(key)); goto done; } if (have_sig) { sig = packet_get_string(&slen); packet_check_eom(); buffer_init(&b); if (datafellows & SSH_OLD_SESSIONID) { buffer_append(&b, session_id2, session_id2_len); } else { buffer_put_string(&b, session_id2, session_id2_len); } /* reconstruct packet */ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", authctxt->style ? authctxt->style : ""); buffer_put_cstring(&b, userstyle); free(userstyle); buffer_put_cstring(&b, datafellows & SSH_BUG_PKSERVICE ? "ssh-userauth" : authctxt->service); if (datafellows & SSH_BUG_PKAUTH) { buffer_put_char(&b, have_sig); } else { buffer_put_cstring(&b, "publickey"); buffer_put_char(&b, have_sig); buffer_put_cstring(&b, pkalg); } buffer_put_string(&b, pkblob, blen); #ifdef DEBUG_PK buffer_dump(&b); #endif pubkey_auth_info(authctxt, key, NULL); /* test for correct signature */ authenticated = 0; /* * On pure win32 try to logon using lsa first. */ #ifdef WIN32_FIXME authctxt -> hTokenLsa_ = NULL; authctxt -> methoddata = NULL; /* * Retrieve name of current login user (i.e. sshd process owner). */ GetUserName(currentUser, ¤tUserSize); /* * Try to get token from lsa, but only if targetUser != currentUser. * Owerthise we already have targetUser's token in current thread, so * we only need key verify from original OpenSSH code. */ targetIsCurrent = (strcmp(currentUser, authctxt -> user) == 0); if (targetIsCurrent) { doOpenSSHVerify = 1; } else { loginStat = LsaLogon(&authctxt -> hTokenLsa_, HomeDirLsaW, authctxt -> user, pkblob, blen, sig, slen, buffer_ptr(&b), buffer_len(&b), datafellows); /* * If lsa logon process success. */ if (loginStat == 0) { /* * And user authorized OK. */ if (authctxt -> hTokenLsa_) { doOpenSSHVerify = 0; /* * This is part of openssh authorization needed for parsing * 'options' block in key. */ authctxt -> pw -> pw_dir = GetHomeDir(authctxt -> user); if (PRIVSEP(user_key_allowed(authctxt -> pw, key, 1))) // PRAGMA:TODO { authenticated = 1; } else { authenticated = 0; } buffer_free(&b); free(sig); } } } if (doOpenSSHVerify) { /* * If lsa fails, test for correct signature using openssh code. */ authctxt -> pw -> pw_dir = GetHomeDir(authctxt -> user); if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0)) //PRAGMA:TODO && PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b))) == 1) { authenticated = 1; } } /* * Original code. */ #else /* #ifdef WIN32_FIXME */ if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b))) == 1) { authenticated = 1; /* Record the successful key to prevent reuse */ auth2_record_userkey(authctxt, key); key = NULL; /* Don't free below */ } buffer_free(&b); free(sig); #endif /* else #ifdef WIN32_FIXME. */ } else { debug("test whether pkalg/pkblob are acceptable"); packet_check_eom(); /* XXX fake reply and always send PK_OK ? */ /* * XXX this allows testing whether a user is allowed * to login: if you happen to have a valid pubkey this * message is sent. the message is NEVER sent at all * if a user is not allowed to login. is this an * issue? -markus */ #ifndef WIN32_FIXME if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) #endif { packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); packet_put_string(pkblob, blen); packet_send(); packet_write_wait(); authctxt->postponed = 1; } } if (authenticated != 1) auth_clear_options(); done: debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); if (key != NULL) key_free(key); free(pkalg); free(pkblob); return authenticated; }
int ssh_ed25519_verify(const Key *key, const u_char *signature, u_int signaturelen, const u_char *data, u_int datalen) { Buffer b; char *ktype; u_char *sigblob, *sm, *m; u_int len; unsigned long long smlen, mlen; int rlen, ret; if (key == NULL || key_type_plain(key->type) != KEY_ED25519 || key->ed25519_pk == NULL) { error("%s: no ED25519 key", __func__); return -1; } buffer_init(&b); buffer_append(&b, signature, signaturelen); ktype = buffer_get_cstring(&b, NULL); if (strcmp("ssh-ed25519", ktype) != 0) { error("%s: cannot handle type %s", __func__, ktype); buffer_free(&b); free(ktype); return -1; } free(ktype); sigblob = buffer_get_string(&b, &len); rlen = buffer_len(&b); buffer_free(&b); if (rlen != 0) { error("%s: remaining bytes in signature %d", __func__, rlen); free(sigblob); return -1; } if (len > crypto_sign_ed25519_BYTES) { error("%s: len %u > crypto_sign_ed25519_BYTES %u", __func__, len, crypto_sign_ed25519_BYTES); free(sigblob); return -1; } smlen = len + datalen; sm = xmalloc(smlen); memcpy(sm, sigblob, len); memcpy(sm+len, data, datalen); mlen = smlen; m = xmalloc(mlen); if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, key->ed25519_pk)) != 0) { debug2("%s: crypto_sign_ed25519_open failed: %d", __func__, ret); } if (ret == 0 && mlen != datalen) { debug2("%s: crypto_sign_ed25519_open " "mlen != datalen (%llu != %u)", __func__, mlen, datalen); ret = -1; } /* XXX compare 'm' and 'data' ? */ explicit_bzero(sigblob, len); explicit_bzero(sm, smlen); explicit_bzero(m, smlen); /* NB. mlen may be invalid if ret != 0 */ free(sigblob); free(sm); free(m); debug("%s: signature %scorrect", __func__, (ret != 0) ? "in" : ""); /* translate return code carefully */ return (ret == 0) ? 1 : -1; }
static int userauth_hostbased(Authctxt *authctxt) { Buffer b; Key *key = NULL; char *pkalg, *cuser, *chost, *service; u_char *pkblob, *sig; u_int alen, blen, slen; int pktype; int authenticated = 0; if (!authctxt->valid) { debug2("userauth_hostbased: disabled because of invalid user"); return 0; } pkalg = packet_get_string(&alen); pkblob = packet_get_string(&blen); chost = packet_get_string(NULL); cuser = packet_get_string(NULL); sig = packet_get_string(&slen); debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d", cuser, chost, pkalg, slen); #ifdef DEBUG_PK debug("signature:"); buffer_init(&b); buffer_append(&b, sig, slen); buffer_dump(&b); buffer_free(&b); #endif pktype = key_type_from_name(pkalg); if (pktype == KEY_UNSPEC) { /* this is perfectly legal */ logit("userauth_hostbased: unsupported " "public key algorithm: %s", pkalg); goto done; } key = key_from_blob(pkblob, blen); if (key == NULL) { error("userauth_hostbased: cannot decode key: %s", pkalg); goto done; } if (key->type != pktype) { error("userauth_hostbased: type mismatch for decoded key " "(received %d, expected %d)", key->type, pktype); goto done; } if (key_type_plain(key->type) == KEY_RSA && (datafellows & SSH_BUG_RSASIGMD5) != 0) { error("Refusing RSA key because peer uses unsafe " "signature format"); goto done; } service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : authctxt->service; buffer_init(&b); buffer_put_string(&b, session_id2, session_id2_len); /* reconstruct packet */ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); buffer_put_cstring(&b, authctxt->user); buffer_put_cstring(&b, service); buffer_put_cstring(&b, "hostbased"); buffer_put_string(&b, pkalg, alen); buffer_put_string(&b, pkblob, blen); buffer_put_cstring(&b, chost); buffer_put_cstring(&b, cuser); #ifdef DEBUG_PK buffer_dump(&b); #endif pubkey_auth_info(authctxt, key, "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(key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b))) == 1) authenticated = 1; buffer_free(&b); done: debug2("userauth_hostbased: authenticated %d", authenticated); if (key != NULL) key_free(key); free(pkalg); free(pkblob); free(cuser); free(chost); free(sig); return authenticated; }
int ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen, const u_char *data, u_int datalen) { ECDSA_SIG *sig; int hash_alg; u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; u_int len, dlen; int rlen, ret; Buffer b, bb; char *ktype; if (key == NULL || key_type_plain(key->type) != KEY_ECDSA || key->ecdsa == NULL) { error("%s: no ECDSA key", __func__); return -1; } /* fetch signature */ buffer_init(&b); buffer_append(&b, signature, signaturelen); ktype = buffer_get_string(&b, NULL); if (strcmp(key_ssh_name_plain(key), ktype) != 0) { error("%s: cannot handle type %s", __func__, ktype); buffer_free(&b); free(ktype); return -1; } free(ktype); sigblob = buffer_get_string(&b, &len); rlen = buffer_len(&b); buffer_free(&b); if (rlen != 0) { error("%s: remaining bytes in signature %d", __func__, rlen); free(sigblob); return -1; } /* parse signature */ if ((sig = ECDSA_SIG_new()) == NULL) fatal("%s: ECDSA_SIG_new failed", __func__); buffer_init(&bb); buffer_append(&bb, sigblob, len); buffer_get_bignum2(&bb, sig->r); buffer_get_bignum2(&bb, sig->s); if (buffer_len(&bb) != 0) fatal("%s: remaining bytes in inner sigblob", __func__); buffer_free(&bb); /* clean up */ explicit_bzero(sigblob, len); free(sigblob); /* hash the data */ hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid); if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { error("%s: bad hash algorithm %d", __func__, hash_alg); return -1; } if (ssh_digest_memory(hash_alg, data, datalen, digest, sizeof(digest)) != 0) { error("%s: digest_memory failed", __func__); return -1; } ret = ECDSA_do_verify(digest, dlen, sig, key->ecdsa); explicit_bzero(digest, sizeof(digest)); ECDSA_SIG_free(sig); debug("%s: signature %s", __func__, ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); return ret; }
int mm_answer_keyallowed(int sock, Buffer *m) { struct sshkey *key; char *cuser, *chost; u_char *blob; u_int bloblen, pubkey_auth_attempt; enum mm_keytype type = 0; int allowed = 0; debug3("%s entering", __func__); type = buffer_get_int(m); cuser = buffer_get_string(m, NULL); chost = buffer_get_string(m, NULL); blob = buffer_get_string(m, &bloblen); pubkey_auth_attempt = buffer_get_int(m); key = key_from_blob(blob, bloblen); debug3("%s: key_from_blob: %p", __func__, key); if (key != NULL && authctxt->valid) { /* These should not make it past the privsep child */ if (key_type_plain(key->type) == KEY_RSA && (datafellows & SSH_BUG_RSASIGMD5) != 0) fatal("%s: passed a SSH_BUG_RSASIGMD5 key", __func__); switch (type) { case MM_USERKEY: allowed = options.pubkey_authentication && !auth2_key_already_used(authctxt, key) && match_pattern_list(sshkey_ssh_name(key), options.pubkey_key_types, 0) == 1 && user_key_allowed(authctxt->pw, key, pubkey_auth_attempt); auth_method = "publickey"; if (options.pubkey_authentication && (!pubkey_auth_attempt || allowed != 1)) auth_clear_options(); break; case MM_HOSTKEY: allowed = options.hostbased_authentication && !auth2_key_already_used(authctxt, key) && match_pattern_list(sshkey_ssh_name(key), options.hostbased_key_types, 0) == 1 && hostbased_key_allowed(authctxt->pw, cuser, chost, key); auth2_record_info(authctxt, "client user \"%.100s\", client host \"%.100s\"", cuser, chost); auth_method = "hostbased"; break; default: fatal("%s: unknown key type %d", __func__, type); break; } } debug3("%s: key is %s", __func__, allowed ? "allowed" : "not allowed"); auth2_record_key(authctxt, 0, key); sshkey_free(key); /* clear temporarily storage (used by verify) */ monitor_reset_key_state(); if (allowed) { /* Save temporarily for comparison in verify */ key_blob = blob; key_bloblen = bloblen; key_blobtype = type; hostbased_cuser = cuser; hostbased_chost = chost; } else { /* Log failed attempt */ auth_log(authctxt, 0, 0, auth_method, NULL); free(blob); free(cuser); free(chost); } buffer_clear(m); buffer_put_int(m, allowed); buffer_put_int(m, forced_command != NULL); mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m); return (0); }