sync with OpenBSD -current
This commit is contained in:
parent
da785accdf
commit
659ea2942e
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmac.c,v 1.17 2023/12/15 13:45:05 tb Exp $ */
|
||||
/* $OpenBSD: cmac.c,v 1.18 2023/12/18 21:15:00 tb Exp $ */
|
||||
/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
|
||||
* project.
|
||||
*/
|
||||
@ -90,21 +90,21 @@ struct CMAC_CTX_st {
|
||||
* and R64 = (1 << 64) | 0x1b for the only supported block sizes 128 and 64.
|
||||
*/
|
||||
static void
|
||||
make_kn(unsigned char *kn, const unsigned char *l, int bl)
|
||||
make_kn(unsigned char *kn, const unsigned char *l, int block_size)
|
||||
{
|
||||
unsigned char mask, Rb;
|
||||
int i;
|
||||
|
||||
/* Choose Rb according to the block size in bytes. */
|
||||
Rb = bl == 16 ? 0x87 : 0x1b;
|
||||
Rb = block_size == 16 ? 0x87 : 0x1b;
|
||||
|
||||
/* Compute l << 1 up to last byte. */
|
||||
for (i = 0; i < bl - 1; i++)
|
||||
for (i = 0; i < block_size - 1; i++)
|
||||
kn[i] = (l[i] << 1) | (l[i + 1] >> 7);
|
||||
|
||||
/* Only xor with Rb if the MSB is one. */
|
||||
mask = 0 - (l[0] >> 7);
|
||||
kn[bl - 1] = (l[bl - 1] << 1) ^ (Rb & mask);
|
||||
kn[block_size - 1] = (l[block_size - 1] << 1) ^ (Rb & mask);
|
||||
}
|
||||
|
||||
CMAC_CTX *
|
||||
@ -154,17 +154,17 @@ LCRYPTO_ALIAS(CMAC_CTX_free);
|
||||
int
|
||||
CMAC_CTX_copy(CMAC_CTX *out, const CMAC_CTX *in)
|
||||
{
|
||||
int bl;
|
||||
int block_size;
|
||||
|
||||
if (in->nlast_block == -1)
|
||||
return 0;
|
||||
if (!EVP_CIPHER_CTX_copy(&out->cctx, &in->cctx))
|
||||
return 0;
|
||||
bl = EVP_CIPHER_CTX_block_size(&in->cctx);
|
||||
memcpy(out->k1, in->k1, bl);
|
||||
memcpy(out->k2, in->k2, bl);
|
||||
memcpy(out->tbl, in->tbl, bl);
|
||||
memcpy(out->last_block, in->last_block, bl);
|
||||
block_size = EVP_CIPHER_CTX_block_size(&in->cctx);
|
||||
memcpy(out->k1, in->k1, block_size);
|
||||
memcpy(out->k2, in->k2, block_size);
|
||||
memcpy(out->tbl, in->tbl, block_size);
|
||||
memcpy(out->last_block, in->last_block, block_size);
|
||||
out->nlast_block = in->nlast_block;
|
||||
return 1;
|
||||
}
|
||||
@ -175,7 +175,7 @@ CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen,
|
||||
const EVP_CIPHER *cipher, ENGINE *impl)
|
||||
{
|
||||
static unsigned char zero_iv[EVP_MAX_BLOCK_LENGTH];
|
||||
int bl;
|
||||
int block_size;
|
||||
|
||||
/* All zeros means restart */
|
||||
if (key == NULL && cipher == NULL && keylen == 0) {
|
||||
@ -208,8 +208,8 @@ CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen,
|
||||
return 0;
|
||||
|
||||
/* make_kn() only supports block sizes of 8 and 16 bytes. */
|
||||
bl = EVP_CIPHER_CTX_block_size(&ctx->cctx);
|
||||
if (bl != 8 && bl != 16)
|
||||
block_size = EVP_CIPHER_CTX_block_size(&ctx->cctx);
|
||||
if (block_size != 8 && block_size != 16)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@ -220,13 +220,13 @@ CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen,
|
||||
return 0;
|
||||
if (!EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, key, zero_iv))
|
||||
return 0;
|
||||
if (!EVP_Cipher(&ctx->cctx, ctx->tbl, zero_iv, bl))
|
||||
if (!EVP_Cipher(&ctx->cctx, ctx->tbl, zero_iv, block_size))
|
||||
return 0;
|
||||
|
||||
/* Section 6.1, step 2: compute k1 from intermediate secret. */
|
||||
make_kn(ctx->k1, ctx->tbl, bl);
|
||||
make_kn(ctx->k1, ctx->tbl, block_size);
|
||||
/* Section 6.1, step 3: compute k2 from k1. */
|
||||
make_kn(ctx->k2, ctx->k1, bl);
|
||||
make_kn(ctx->k2, ctx->k1, block_size);
|
||||
|
||||
/* Destroy intermediate secret and reset last block count. */
|
||||
explicit_bzero(ctx->tbl, sizeof(ctx->tbl));
|
||||
@ -245,18 +245,18 @@ int
|
||||
CMAC_Update(CMAC_CTX *ctx, const void *in, size_t dlen)
|
||||
{
|
||||
const unsigned char *data = in;
|
||||
size_t bl;
|
||||
size_t block_size;
|
||||
|
||||
if (ctx->nlast_block == -1)
|
||||
return 0;
|
||||
if (dlen == 0)
|
||||
return 1;
|
||||
bl = EVP_CIPHER_CTX_block_size(&ctx->cctx);
|
||||
block_size = EVP_CIPHER_CTX_block_size(&ctx->cctx);
|
||||
/* Copy into partial block if we need to */
|
||||
if (ctx->nlast_block > 0) {
|
||||
size_t nleft;
|
||||
|
||||
nleft = bl - ctx->nlast_block;
|
||||
nleft = block_size - ctx->nlast_block;
|
||||
if (dlen < nleft)
|
||||
nleft = dlen;
|
||||
memcpy(ctx->last_block + ctx->nlast_block, data, nleft);
|
||||
@ -267,15 +267,16 @@ CMAC_Update(CMAC_CTX *ctx, const void *in, size_t dlen)
|
||||
return 1;
|
||||
data += nleft;
|
||||
/* Else not final block so encrypt it */
|
||||
if (!EVP_Cipher(&ctx->cctx, ctx->tbl, ctx->last_block, bl))
|
||||
if (!EVP_Cipher(&ctx->cctx, ctx->tbl, ctx->last_block,
|
||||
block_size))
|
||||
return 0;
|
||||
}
|
||||
/* Encrypt all but one of the complete blocks left */
|
||||
while (dlen > bl) {
|
||||
if (!EVP_Cipher(&ctx->cctx, ctx->tbl, data, bl))
|
||||
while (dlen > block_size) {
|
||||
if (!EVP_Cipher(&ctx->cctx, ctx->tbl, data, block_size))
|
||||
return 0;
|
||||
dlen -= bl;
|
||||
data += bl;
|
||||
dlen -= block_size;
|
||||
data += block_size;
|
||||
}
|
||||
/* Copy any data left to last block buffer */
|
||||
memcpy(ctx->last_block, data, dlen);
|
||||
@ -287,28 +288,28 @@ LCRYPTO_ALIAS(CMAC_Update);
|
||||
int
|
||||
CMAC_Final(CMAC_CTX *ctx, unsigned char *out, size_t *poutlen)
|
||||
{
|
||||
int i, bl, lb;
|
||||
int i, block_size, lb;
|
||||
|
||||
if (ctx->nlast_block == -1)
|
||||
return 0;
|
||||
bl = EVP_CIPHER_CTX_block_size(&ctx->cctx);
|
||||
*poutlen = (size_t)bl;
|
||||
block_size = EVP_CIPHER_CTX_block_size(&ctx->cctx);
|
||||
*poutlen = (size_t)block_size;
|
||||
if (!out)
|
||||
return 1;
|
||||
lb = ctx->nlast_block;
|
||||
/* Is last block complete? */
|
||||
if (lb == bl) {
|
||||
for (i = 0; i < bl; i++)
|
||||
if (lb == block_size) {
|
||||
for (i = 0; i < block_size; i++)
|
||||
out[i] = ctx->last_block[i] ^ ctx->k1[i];
|
||||
} else {
|
||||
ctx->last_block[lb] = 0x80;
|
||||
if (bl - lb > 1)
|
||||
memset(ctx->last_block + lb + 1, 0, bl - lb - 1);
|
||||
for (i = 0; i < bl; i++)
|
||||
if (block_size - lb > 1)
|
||||
memset(ctx->last_block + lb + 1, 0, block_size - lb - 1);
|
||||
for (i = 0; i < block_size; i++)
|
||||
out[i] = ctx->last_block[i] ^ ctx->k2[i];
|
||||
}
|
||||
if (!EVP_Cipher(&ctx->cctx, out, out, bl)) {
|
||||
explicit_bzero(out, bl);
|
||||
if (!EVP_Cipher(&ctx->cctx, out, out, block_size)) {
|
||||
explicit_bzero(out, block_size);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: evp_pbe.c,v 1.33 2023/12/16 14:09:33 tb Exp $ */
|
||||
/* $OpenBSD: evp_pbe.c,v 1.34 2023/12/18 13:12:43 tb Exp $ */
|
||||
/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
|
||||
* project 1999.
|
||||
*/
|
||||
@ -269,43 +269,35 @@ int
|
||||
EVP_PBE_CipherInit(ASN1_OBJECT *pbe_obj, const char *pass, int passlen,
|
||||
ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de)
|
||||
{
|
||||
const EVP_CIPHER *cipher;
|
||||
const EVP_MD *md;
|
||||
int cipher_nid, md_nid;
|
||||
const EVP_CIPHER *cipher = NULL;
|
||||
const EVP_MD *md = NULL;
|
||||
int pbe_nid, cipher_nid, md_nid;
|
||||
EVP_PBE_KEYGEN *keygen;
|
||||
|
||||
if (!EVP_PBE_find(EVP_PBE_TYPE_OUTER, OBJ_obj2nid(pbe_obj),
|
||||
&cipher_nid, &md_nid, &keygen)) {
|
||||
char obj_tmp[80];
|
||||
if ((pbe_nid = OBJ_obj2nid(pbe_obj)) == NID_undef) {
|
||||
EVPerror(EVP_R_UNKNOWN_PBE_ALGORITHM);
|
||||
if (!pbe_obj)
|
||||
strlcpy(obj_tmp, "NULL", sizeof obj_tmp);
|
||||
else
|
||||
i2t_ASN1_OBJECT(obj_tmp, sizeof obj_tmp, pbe_obj);
|
||||
ERR_asprintf_error_data("TYPE=%s", obj_tmp);
|
||||
return 0;
|
||||
}
|
||||
if (!EVP_PBE_find(EVP_PBE_TYPE_OUTER, pbe_nid, &cipher_nid, &md_nid,
|
||||
&keygen)) {
|
||||
EVPerror(EVP_R_UNKNOWN_PBE_ALGORITHM);
|
||||
ERR_asprintf_error_data("NID=%d", pbe_nid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pass)
|
||||
if (pass == NULL)
|
||||
passlen = 0;
|
||||
else if (passlen == -1)
|
||||
if (passlen == -1)
|
||||
passlen = strlen(pass);
|
||||
|
||||
if (cipher_nid == -1)
|
||||
cipher = NULL;
|
||||
else {
|
||||
cipher = EVP_get_cipherbynid(cipher_nid);
|
||||
if (!cipher) {
|
||||
if (cipher_nid != -1) {
|
||||
if ((cipher = EVP_get_cipherbynid(cipher_nid)) == NULL) {
|
||||
EVPerror(EVP_R_UNKNOWN_CIPHER);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (md_nid == -1)
|
||||
md = NULL;
|
||||
else {
|
||||
md = EVP_get_digestbynid(md_nid);
|
||||
if (!md) {
|
||||
if (md_nid != -1) {
|
||||
if ((md = EVP_get_digestbynid(md_nid)) == NULL) {
|
||||
EVPerror(EVP_R_UNKNOWN_DIGEST);
|
||||
return 0;
|
||||
}
|
||||
@ -315,6 +307,7 @@ EVP_PBE_CipherInit(ASN1_OBJECT *pbe_obj, const char *pass, int passlen,
|
||||
EVPerror(EVP_R_KEYGEN_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -9,25 +9,7 @@
|
||||
|
||||
#include "fido.h"
|
||||
|
||||
#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050200fL
|
||||
static EVP_MD *
|
||||
rs1_get_EVP_MD(void)
|
||||
{
|
||||
const EVP_MD *from;
|
||||
EVP_MD *to = NULL;
|
||||
|
||||
if ((from = EVP_sha1()) != NULL && (to = malloc(sizeof(*to))) != NULL)
|
||||
memcpy(to, from, sizeof(*to));
|
||||
|
||||
return (to);
|
||||
}
|
||||
|
||||
static void
|
||||
rs1_free_EVP_MD(EVP_MD *md)
|
||||
{
|
||||
freezero(md, sizeof(*md));
|
||||
}
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x30000000
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000
|
||||
static EVP_MD *
|
||||
rs1_get_EVP_MD(void)
|
||||
{
|
||||
@ -43,20 +25,15 @@ rs1_free_EVP_MD(EVP_MD *md)
|
||||
static EVP_MD *
|
||||
rs1_get_EVP_MD(void)
|
||||
{
|
||||
const EVP_MD *md;
|
||||
|
||||
if ((md = EVP_sha1()) == NULL)
|
||||
return (NULL);
|
||||
|
||||
return (EVP_MD_meth_dup(md));
|
||||
return ((EVP_MD *)EVP_sha1());
|
||||
}
|
||||
|
||||
static void
|
||||
rs1_free_EVP_MD(EVP_MD *md)
|
||||
{
|
||||
EVP_MD_meth_free(md);
|
||||
(void)md;
|
||||
}
|
||||
#endif /* LIBRESSL_VERSION_NUMBER */
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
int
|
||||
rs1_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
|
||||
|
@ -17,25 +17,7 @@
|
||||
#define get0_RSA(x) EVP_PKEY_get0((x))
|
||||
#endif
|
||||
|
||||
#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050200fL
|
||||
static EVP_MD *
|
||||
rs256_get_EVP_MD(void)
|
||||
{
|
||||
const EVP_MD *from;
|
||||
EVP_MD *to = NULL;
|
||||
|
||||
if ((from = EVP_sha256()) != NULL && (to = malloc(sizeof(*to))) != NULL)
|
||||
memcpy(to, from, sizeof(*to));
|
||||
|
||||
return (to);
|
||||
}
|
||||
|
||||
static void
|
||||
rs256_free_EVP_MD(EVP_MD *md)
|
||||
{
|
||||
freezero(md, sizeof(*md));
|
||||
}
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x30000000
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000
|
||||
static EVP_MD *
|
||||
rs256_get_EVP_MD(void)
|
||||
{
|
||||
@ -51,20 +33,15 @@ rs256_free_EVP_MD(EVP_MD *md)
|
||||
static EVP_MD *
|
||||
rs256_get_EVP_MD(void)
|
||||
{
|
||||
const EVP_MD *md;
|
||||
|
||||
if ((md = EVP_sha256()) == NULL)
|
||||
return (NULL);
|
||||
|
||||
return (EVP_MD_meth_dup(md));
|
||||
return ((EVP_MD *)EVP_sha256());
|
||||
}
|
||||
|
||||
static void
|
||||
rs256_free_EVP_MD(EVP_MD *md)
|
||||
{
|
||||
EVP_MD_meth_free(md);
|
||||
(void)md;
|
||||
}
|
||||
#endif /* LIBRESSL_VERSION_NUMBER */
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
static int
|
||||
decode_bignum(const cbor_item_t *item, void *ptr, size_t len)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: loader.c,v 1.215 2023/12/12 15:44:00 deraadt Exp $ */
|
||||
/* $OpenBSD: loader.c,v 1.216 2023/12/18 17:19:07 deraadt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
|
||||
@ -476,13 +476,13 @@ _dl_self_relro(long loff)
|
||||
#define __STRINGIFY(x) #x
|
||||
#define STRINGIFY(x) __STRINGIFY(x)
|
||||
#ifdef __arm__
|
||||
__asm__(".pushsection openbsd.syscalls,\"\",%progbits;"
|
||||
__asm__(".pushsection .openbsd.syscalls,\"\",%progbits;"
|
||||
".p2align 2;"
|
||||
".long 0;"
|
||||
".long " STRINGIFY(SYS_kbind) ";"
|
||||
".popsection");
|
||||
#else
|
||||
__asm__(".pushsection openbsd.syscalls,\"\",@progbits;"
|
||||
__asm__(".pushsection .openbsd.syscalls,\"\",@progbits;"
|
||||
".long 0;"
|
||||
".p2align 2;"
|
||||
".long " STRINGIFY(SYS_kbind) ";"
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $OpenBSD: Makefile,v 1.129 2023/10/26 18:52:45 anton Exp $
|
||||
# $OpenBSD: Makefile,v 1.131 2023/12/18 14:50:08 djm Exp $
|
||||
|
||||
OPENSSL?= yes
|
||||
|
||||
@ -100,7 +100,9 @@ LTESTS= connect \
|
||||
hostbased \
|
||||
channel-timeout \
|
||||
connection-timeout \
|
||||
match-subsystem
|
||||
match-subsystem \
|
||||
agent-pkcs11-restrict \
|
||||
agent-pkcs11-cert
|
||||
|
||||
INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers
|
||||
INTEROP_TESTS+= dropbear-ciphers dropbear-kex
|
||||
|
92
regress/usr.bin/ssh/agent-pkcs11-cert.sh
Normal file
92
regress/usr.bin/ssh/agent-pkcs11-cert.sh
Normal file
@ -0,0 +1,92 @@
|
||||
# $OpenBSD: agent-pkcs11-cert.sh,v 1.1 2023/12/18 14:50:08 djm Exp $
|
||||
# Placed in the Public Domain.
|
||||
|
||||
tid="pkcs11 agent certificate test"
|
||||
|
||||
SSH_AUTH_SOCK="$OBJ/agent.sock"
|
||||
export SSH_AUTH_SOCK
|
||||
LC_ALL=C
|
||||
export LC_ALL
|
||||
p11_setup || skip "No PKCS#11 library found"
|
||||
|
||||
rm -f $SSH_AUTH_SOCK $OBJ/agent.log
|
||||
rm -f $OBJ/output_* $OBJ/expect_*
|
||||
rm -f $OBJ/ca*
|
||||
|
||||
trace "generate CA key and certify keys"
|
||||
$SSHKEYGEN -q -t ed25519 -C ca -N '' -f $OBJ/ca || fatal "ssh-keygen CA failed"
|
||||
$SSHKEYGEN -qs $OBJ/ca -I "ecdsa_key" -n $USER -z 1 ${SSH_SOFTHSM_DIR}/EC.pub ||
|
||||
fatal "certify ECDSA key failed"
|
||||
$SSHKEYGEN -qs $OBJ/ca -I "rsa_key" -n $USER -z 2 ${SSH_SOFTHSM_DIR}/RSA.pub ||
|
||||
fatal "certify RSA key failed"
|
||||
$SSHKEYGEN -qs $OBJ/ca -I "ca_ca" -n $USER -z 3 $OBJ/ca.pub ||
|
||||
fatal "certify CA key failed"
|
||||
|
||||
rm -f $SSH_AUTH_SOCK
|
||||
trace "start agent"
|
||||
${SSHAGENT} ${EXTRA_AGENT_ARGS} -d -a $SSH_AUTH_SOCK > $OBJ/agent.log 2>&1 &
|
||||
AGENT_PID=$!
|
||||
trap "kill $AGENT_PID" EXIT
|
||||
for x in 0 1 2 3 4 ; do
|
||||
# Give it a chance to start
|
||||
${SSHADD} -l > /dev/null 2>&1
|
||||
r=$?
|
||||
test $r -eq 1 && break
|
||||
sleep 1
|
||||
done
|
||||
if [ $r -ne 1 ]; then
|
||||
fatal "ssh-add -l did not fail with exit code 1 (got $r)"
|
||||
fi
|
||||
|
||||
trace "load pkcs11 keys and certs"
|
||||
# Note: deliberately contains non-cert keys and non-matching cert on commandline
|
||||
p11_ssh_add -qs ${TEST_SSH_PKCS11} \
|
||||
$OBJ/ca.pub \
|
||||
${SSH_SOFTHSM_DIR}/EC.pub \
|
||||
${SSH_SOFTHSM_DIR}/EC-cert.pub \
|
||||
${SSH_SOFTHSM_DIR}/RSA.pub \
|
||||
${SSH_SOFTHSM_DIR}/RSA-cert.pub ||
|
||||
fatal "failed to add keys"
|
||||
# Verify their presence
|
||||
cut -d' ' -f1-2 \
|
||||
${SSH_SOFTHSM_DIR}/EC.pub \
|
||||
${SSH_SOFTHSM_DIR}/RSA.pub \
|
||||
${SSH_SOFTHSM_DIR}/EC-cert.pub \
|
||||
${SSH_SOFTHSM_DIR}/RSA-cert.pub | sort > $OBJ/expect_list
|
||||
$SSHADD -L | cut -d' ' -f1-2 | sort > $OBJ/output_list
|
||||
diff $OBJ/expect_list $OBJ/output_list
|
||||
|
||||
# Verify that all can perform signatures.
|
||||
for x in ${SSH_SOFTHSM_DIR}/EC.pub ${SSH_SOFTHSM_DIR}/RSA.pub \
|
||||
${SSH_SOFTHSM_DIR}/EC-cert.pub ${SSH_SOFTHSM_DIR}/RSA-cert.pub ; do
|
||||
$SSHADD -T $x || fail "Signing failed for $x"
|
||||
done
|
||||
|
||||
# Delete plain keys.
|
||||
$SSHADD -qd ${SSH_SOFTHSM_DIR}/EC.pub ${SSH_SOFTHSM_DIR}/RSA.pub
|
||||
# Verify that certs can still perform signatures.
|
||||
for x in ${SSH_SOFTHSM_DIR}/EC-cert.pub ${SSH_SOFTHSM_DIR}/RSA-cert.pub ; do
|
||||
$SSHADD -T $x || fail "Signing failed for $x"
|
||||
done
|
||||
|
||||
$SSHADD -qD >/dev/null || fatal "clear agent failed"
|
||||
|
||||
trace "load pkcs11 certs only"
|
||||
p11_ssh_add -qCs ${TEST_SSH_PKCS11} \
|
||||
$OBJ/ca.pub \
|
||||
${SSH_SOFTHSM_DIR}/EC.pub \
|
||||
${SSH_SOFTHSM_DIR}/EC-cert.pub \
|
||||
${SSH_SOFTHSM_DIR}/RSA.pub \
|
||||
${SSH_SOFTHSM_DIR}/RSA-cert.pub ||
|
||||
fatal "failed to add keys"
|
||||
# Verify their presence
|
||||
cut -d' ' -f1-2 \
|
||||
${SSH_SOFTHSM_DIR}/EC-cert.pub \
|
||||
${SSH_SOFTHSM_DIR}/RSA-cert.pub | sort > $OBJ/expect_list
|
||||
$SSHADD -L | cut -d' ' -f1-2 | sort > $OBJ/output_list
|
||||
diff $OBJ/expect_list $OBJ/output_list
|
||||
|
||||
# Verify that certs can perform signatures.
|
||||
for x in ${SSH_SOFTHSM_DIR}/EC-cert.pub ${SSH_SOFTHSM_DIR}/RSA-cert.pub ; do
|
||||
$SSHADD -T $x || fail "Signing failed for $x"
|
||||
done
|
193
regress/usr.bin/ssh/agent-pkcs11-restrict.sh
Normal file
193
regress/usr.bin/ssh/agent-pkcs11-restrict.sh
Normal file
@ -0,0 +1,193 @@
|
||||
# $OpenBSD: agent-pkcs11-restrict.sh,v 1.1 2023/12/18 14:49:39 djm Exp $
|
||||
# Placed in the Public Domain.
|
||||
|
||||
tid="pkcs11 agent constraint test"
|
||||
|
||||
p11_setup || skip "No PKCS#11 library found"
|
||||
|
||||
rm -f $SSH_AUTH_SOCK $OBJ/agent.log $OBJ/host_[abcx]* $OBJ/user_[abcx]*
|
||||
rm -f $OBJ/sshd_proxy_host* $OBJ/ssh_output* $OBJ/expect_*
|
||||
rm -f $OBJ/ssh_proxy[._]* $OBJ/command $OBJ/authorized_keys_*
|
||||
|
||||
trace "generate host keys"
|
||||
for h in a b x ca ; do
|
||||
$SSHKEYGEN -q -t ed25519 -C host_$h -N '' -f $OBJ/host_$h || \
|
||||
fatal "ssh-keygen hostkey failed"
|
||||
done
|
||||
|
||||
# XXX test CA hostcerts too.
|
||||
|
||||
key_for() {
|
||||
case $h in
|
||||
a) K="${SSH_SOFTHSM_DIR}/RSA.pub" ;;
|
||||
b) K="${SSH_SOFTHSM_DIR}/EC.pub" ;;
|
||||
*) K="" ;;
|
||||
esac
|
||||
export K
|
||||
}
|
||||
|
||||
SSH_AUTH_SOCK="$OBJ/agent.sock"
|
||||
export SSH_AUTH_SOCK
|
||||
rm -f $SSH_AUTH_SOCK
|
||||
trace "start agent"
|
||||
${SSHAGENT} ${EXTRA_AGENT_ARGS} -d -a $SSH_AUTH_SOCK > $OBJ/agent.log 2>&1 &
|
||||
AGENT_PID=$!
|
||||
trap "kill $AGENT_PID" EXIT
|
||||
for x in 0 1 2 3 4 ; do
|
||||
# Give it a chance to start
|
||||
${SSHADD} -l > /dev/null 2>&1
|
||||
r=$?
|
||||
test $r -eq 1 && break
|
||||
sleep 1
|
||||
done
|
||||
if [ $r -ne 1 ]; then
|
||||
fatal "ssh-add -l did not fail with exit code 1 (got $r)"
|
||||
fi
|
||||
|
||||
# XXX a lot of this is a copy of agent-restrict.sh, but I couldn't see a nice
|
||||
# way to factor it out -djm
|
||||
|
||||
trace "prepare client config"
|
||||
egrep -vi '(identityfile|hostname|hostkeyalias|proxycommand)' \
|
||||
$OBJ/ssh_proxy > $OBJ/ssh_proxy.bak
|
||||
cat << _EOF > $OBJ/ssh_proxy
|
||||
IdentitiesOnly yes
|
||||
ForwardAgent yes
|
||||
ExitOnForwardFailure yes
|
||||
_EOF
|
||||
cp $OBJ/ssh_proxy $OBJ/ssh_proxy_noid
|
||||
for h in a b ; do
|
||||
key_for $h
|
||||
cat << _EOF >> $OBJ/ssh_proxy
|
||||
Host host_$h
|
||||
Hostname host_$h
|
||||
HostkeyAlias host_$h
|
||||
IdentityFile $K
|
||||
ProxyCommand ${SUDO} env SSH_SK_HELPER=\"$SSH_SK_HELPER\" ${OBJ}/sshd-log-wrapper.sh -i -f $OBJ/sshd_proxy_host_$h
|
||||
_EOF
|
||||
# Variant with no specified keys.
|
||||
cat << _EOF >> $OBJ/ssh_proxy_noid
|
||||
Host host_$h
|
||||
Hostname host_$h
|
||||
HostkeyAlias host_$h
|
||||
ProxyCommand ${SUDO} env SSH_SK_HELPER=\"$SSH_SK_HELPER\" ${OBJ}/sshd-log-wrapper.sh -i -f $OBJ/sshd_proxy_host_$h
|
||||
_EOF
|
||||
done
|
||||
cat $OBJ/ssh_proxy.bak >> $OBJ/ssh_proxy
|
||||
cat $OBJ/ssh_proxy.bak >> $OBJ/ssh_proxy_noid
|
||||
|
||||
LC_ALL=C
|
||||
export LC_ALL
|
||||
echo "SetEnv LC_ALL=${LC_ALL}" >> sshd_proxy
|
||||
|
||||
trace "prepare known_hosts"
|
||||
rm -f $OBJ/known_hosts
|
||||
for h in a b x ; do
|
||||
(printf "host_$h " ; cat $OBJ/host_${h}.pub) >> $OBJ/known_hosts
|
||||
done
|
||||
|
||||
trace "prepare server configs"
|
||||
egrep -vi '(hostkey|pidfile)' $OBJ/sshd_proxy \
|
||||
> $OBJ/sshd_proxy.bak
|
||||
for h in a b ; do
|
||||
cp $OBJ/sshd_proxy.bak $OBJ/sshd_proxy_host_$h
|
||||
cat << _EOF >> $OBJ/sshd_proxy_host_$h
|
||||
ExposeAuthInfo yes
|
||||
Hostkey $OBJ/host_$h
|
||||
_EOF
|
||||
cp $OBJ/sshd_proxy_host_$h $OBJ/sshd_proxy_host_${h}.bak
|
||||
done
|
||||
|
||||
trace "prepare authorized_keys"
|
||||
cat >> $OBJ/command << EOF
|
||||
#!/bin/sh
|
||||
echo USERAUTH
|
||||
cat \$SSH_USER_AUTH
|
||||
echo AGENT
|
||||
if $SSHADD -ql >/dev/null 2>&1 ; then
|
||||
$SSHADD -L | cut -d' ' -f1-2 | sort
|
||||
else
|
||||
echo NONE
|
||||
fi
|
||||
EOF
|
||||
chmod a+x $OBJ/command
|
||||
>$OBJ/authorized_keys_$USER
|
||||
for h in a b ; do
|
||||
key_for $h
|
||||
(printf "%s" "restrict,agent-forwarding,command=\"$OBJ/command\" ";
|
||||
cat $K) >> $OBJ/authorized_keys_$USER
|
||||
done
|
||||
|
||||
trace "unrestricted keys"
|
||||
$SSHADD -qD >/dev/null || fatal "clear agent failed"
|
||||
p11_ssh_add -qs ${TEST_SSH_PKCS11} ||
|
||||
fatal "failed to add keys"
|
||||
for h in a b ; do
|
||||
key_for $h
|
||||
echo USERAUTH > $OBJ/expect_$h
|
||||
printf "publickey " >> $OBJ/expect_$h
|
||||
cat $K >> $OBJ/expect_$h
|
||||
echo AGENT >> $OBJ/expect_$h
|
||||
$SSHADD -L | cut -d' ' -f1-2 | sort >> $OBJ/expect_$h
|
||||
${SSH} -F $OBJ/ssh_proxy -oIdentityFile=$K \
|
||||
host_$h true > $OBJ/ssh_output || fatal "test ssh $h failed"
|
||||
cmp $OBJ/expect_$h $OBJ/ssh_output || fatal "unexpected output"
|
||||
done
|
||||
|
||||
trace "restricted to different host"
|
||||
$SSHADD -qD >/dev/null || fatal "clear agent failed"
|
||||
p11_ssh_add -q -h host_x -s ${TEST_SSH_PKCS11} -H $OBJ/known_hosts ||
|
||||
fatal "failed to add keys"
|
||||
for h in a b ; do
|
||||
key_for $h
|
||||
${SSH} -F $OBJ/ssh_proxy -oIdentityFile=$K \
|
||||
host_$h true > $OBJ/ssh_output && fatal "test ssh $h succeeded"
|
||||
done
|
||||
|
||||
trace "restricted to destination host"
|
||||
$SSHADD -qD >/dev/null || fatal "clear agent failed"
|
||||
p11_ssh_add -q -h host_a -h host_b -s ${TEST_SSH_PKCS11} -H $OBJ/known_hosts ||
|
||||
fatal "failed to add keys"
|
||||
for h in a b ; do
|
||||
key_for $h
|
||||
echo USERAUTH > $OBJ/expect_$h
|
||||
printf "publickey " >> $OBJ/expect_$h
|
||||
cat $K >> $OBJ/expect_$h
|
||||
echo AGENT >> $OBJ/expect_$h
|
||||
echo NONE >> $OBJ/expect_$h
|
||||
${SSH} -F $OBJ/ssh_proxy -oIdentityFile=$K \
|
||||
host_$h true > $OBJ/ssh_output || fatal "test ssh $h failed"
|
||||
cmp $OBJ/expect_$h $OBJ/ssh_output || fatal "unexpected output"
|
||||
done
|
||||
|
||||
trace "restricted multihop"
|
||||
$SSHADD -qD >/dev/null || fatal "clear agent failed"
|
||||
p11_ssh_add -q -h host_a -h "host_a>host_b" \
|
||||
-s ${TEST_SSH_PKCS11} -H $OBJ/known_hosts || fatal "failed to add keys"
|
||||
key_for a
|
||||
AK=$K
|
||||
key_for b
|
||||
BK=$K
|
||||
# Prepare authorized_keys file to additionally ssh to host_b
|
||||
_command="echo LOCAL ; ${OBJ}/command ; echo REMOTE; ${SSH} -AF $OBJ/ssh_proxy -oIdentityFile=$BK host_b"
|
||||
(printf "%s" "restrict,agent-forwarding,command=\"$_command\" ";
|
||||
cat $BK) > $OBJ/authorized_keys_a
|
||||
grep -vi AuthorizedKeysFile $OBJ/sshd_proxy_host_a.bak > $OBJ/sshd_proxy_host_a
|
||||
echo "AuthorizedKeysFile $OBJ/authorized_keys_a" >> $OBJ/sshd_proxy_host_a
|
||||
# Prepare expected output from both hosts.
|
||||
echo LOCAL > $OBJ/expect_a
|
||||
echo USERAUTH >> $OBJ/expect_a
|
||||
printf "publickey " >> $OBJ/expect_a
|
||||
cat $AK >> $OBJ/expect_a
|
||||
echo AGENT >> $OBJ/expect_a
|
||||
$SSHADD -L | cut -d' ' -f1-2 | sort >> $OBJ/expect_a
|
||||
echo REMOTE >> $OBJ/expect_a
|
||||
echo USERAUTH >> $OBJ/expect_a
|
||||
printf "publickey " >> $OBJ/expect_a
|
||||
cat $BK >> $OBJ/expect_a
|
||||
echo AGENT >> $OBJ/expect_a
|
||||
echo NONE >> $OBJ/expect_a
|
||||
${SSH} -AF $OBJ/ssh_proxy -oIdentityFile=$AK \
|
||||
host_a whatever > $OBJ/ssh_output || fatal "test ssh $h failed"
|
||||
cmp $OBJ/expect_a $OBJ/ssh_output || fatal "unexpected output"
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: main.c,v 1.63 2022/06/02 15:35:55 millert Exp $ */
|
||||
/* $OpenBSD: main.c,v 1.64 2023/12/18 13:23:52 otto Exp $ */
|
||||
/* $NetBSD: main.c,v 1.14 1997/06/05 11:13:24 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
@ -465,6 +465,9 @@ main(int argc, char *argv[])
|
||||
usedinomap = calloc((unsigned) mapsize, sizeof(char));
|
||||
dumpdirmap = calloc((unsigned) mapsize, sizeof(char));
|
||||
dumpinomap = calloc((unsigned) mapsize, sizeof(char));
|
||||
if (usedinomap == NULL || dumpdirmap == NULL || dumpinomap == NULL)
|
||||
quit("Failed to allocate tables");
|
||||
|
||||
tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
|
||||
|
||||
nonodump = spcl.c_level < honorlevel;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: uipc_socket.c,v 1.309 2023/08/08 22:07:25 mvs Exp $ */
|
||||
/* $OpenBSD: uipc_socket.c,v 1.310 2023/12/18 13:11:20 bluhm Exp $ */
|
||||
/* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */
|
||||
|
||||
/*
|
||||
@ -832,8 +832,10 @@ bad:
|
||||
*mp = NULL;
|
||||
|
||||
solock_shared(so);
|
||||
pru_lock(so);
|
||||
restart:
|
||||
if ((error = sblock(so, &so->so_rcv, SBLOCKWAIT(flags))) != 0) {
|
||||
pru_unlock(so);
|
||||
sounlock_shared(so);
|
||||
return (error);
|
||||
}
|
||||
@ -900,11 +902,13 @@ restart:
|
||||
SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 1");
|
||||
SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 1");
|
||||
sbunlock(so, &so->so_rcv);
|
||||
pru_unlock(so);
|
||||
error = sbwait(so, &so->so_rcv);
|
||||
if (error) {
|
||||
sounlock_shared(so);
|
||||
return (error);
|
||||
}
|
||||
pru_lock(so);
|
||||
goto restart;
|
||||
}
|
||||
dontblock:
|
||||
@ -971,11 +975,13 @@ dontblock:
|
||||
sbsync(&so->so_rcv, nextrecord);
|
||||
if (controlp) {
|
||||
if (pr->pr_domain->dom_externalize) {
|
||||
pru_unlock(so);
|
||||
sounlock_shared(so);
|
||||
error =
|
||||
(*pr->pr_domain->dom_externalize)
|
||||
(cm, controllen, flags);
|
||||
solock_shared(so);
|
||||
pru_lock(so);
|
||||
}
|
||||
*controlp = cm;
|
||||
} else {
|
||||
@ -1049,9 +1055,11 @@ dontblock:
|
||||
SBLASTRECORDCHK(&so->so_rcv, "soreceive uiomove");
|
||||
SBLASTMBUFCHK(&so->so_rcv, "soreceive uiomove");
|
||||
resid = uio->uio_resid;
|
||||
pru_unlock(so);
|
||||
sounlock_shared(so);
|
||||
uio_error = uiomove(mtod(m, caddr_t) + moff, len, uio);
|
||||
solock_shared(so);
|
||||
pru_lock(so);
|
||||
if (uio_error)
|
||||
uio->uio_resid = resid - len;
|
||||
} else
|
||||
@ -1136,6 +1144,7 @@ dontblock:
|
||||
error = sbwait(so, &so->so_rcv);
|
||||
if (error) {
|
||||
sbunlock(so, &so->so_rcv);
|
||||
pru_unlock(so);
|
||||
sounlock_shared(so);
|
||||
return (0);
|
||||
}
|
||||
@ -1182,6 +1191,7 @@ dontblock:
|
||||
*flagsp |= flags;
|
||||
release:
|
||||
sbunlock(so, &so->so_rcv);
|
||||
pru_unlock(so);
|
||||
sounlock_shared(so);
|
||||
return (error);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: uipc_socket2.c,v 1.138 2023/10/30 13:27:53 bluhm Exp $ */
|
||||
/* $OpenBSD: uipc_socket2.c,v 1.139 2023/12/18 13:11:20 bluhm Exp $ */
|
||||
/* $NetBSD: uipc_socket2.c,v 1.11 1996/02/04 02:17:55 christos Exp $ */
|
||||
|
||||
/*
|
||||
@ -368,7 +368,7 @@ solock_shared(struct socket *so)
|
||||
case PF_INET6:
|
||||
if (so->so_proto->pr_usrreqs->pru_lock != NULL) {
|
||||
NET_LOCK_SHARED();
|
||||
pru_lock(so);
|
||||
rw_enter_write(&so->so_lock);
|
||||
} else
|
||||
NET_LOCK();
|
||||
break;
|
||||
@ -427,7 +427,7 @@ sounlock_shared(struct socket *so)
|
||||
case PF_INET:
|
||||
case PF_INET6:
|
||||
if (so->so_proto->pr_usrreqs->pru_unlock != NULL) {
|
||||
pru_unlock(so);
|
||||
rw_exit_write(&so->so_lock);
|
||||
NET_UNLOCK_SHARED();
|
||||
} else
|
||||
NET_UNLOCK();
|
||||
@ -463,12 +463,12 @@ sosleep_nsec(struct socket *so, void *ident, int prio, const char *wmesg,
|
||||
case PF_INET6:
|
||||
if (so->so_proto->pr_usrreqs->pru_unlock != NULL &&
|
||||
rw_status(&netlock) == RW_READ) {
|
||||
pru_unlock(so);
|
||||
rw_exit_write(&so->so_lock);
|
||||
}
|
||||
ret = rwsleep_nsec(ident, &netlock, prio, wmesg, nsecs);
|
||||
if (so->so_proto->pr_usrreqs->pru_lock != NULL &&
|
||||
rw_status(&netlock) == RW_READ) {
|
||||
pru_lock(so);
|
||||
rw_enter_write(&so->so_lock);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: uipc_syscalls.c,v 1.214 2023/09/23 09:17:21 jan Exp $ */
|
||||
/* $OpenBSD: uipc_syscalls.c,v 1.215 2023/12/18 13:11:20 bluhm Exp $ */
|
||||
/* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */
|
||||
|
||||
/*
|
||||
@ -185,9 +185,9 @@ sys_bind(struct proc *p, void *v, register_t *retval)
|
||||
if (KTRPOINT(p, KTR_STRUCT))
|
||||
ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen));
|
||||
#endif
|
||||
solock(so);
|
||||
solock_shared(so);
|
||||
error = sobind(so, nam, p);
|
||||
sounlock(so);
|
||||
sounlock_shared(so);
|
||||
m_freem(nam);
|
||||
out:
|
||||
FRELE(fp, p);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: if_ether.c,v 1.266 2023/11/09 21:45:18 bluhm Exp $ */
|
||||
/* $OpenBSD: if_ether.c,v 1.267 2023/12/18 13:30:44 bluhm Exp $ */
|
||||
/* $NetBSD: if_ether.c,v 1.31 1996/05/11 12:59:58 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
@ -756,7 +756,8 @@ arptfree(struct rtentry *rt)
|
||||
arpinvalidate(rt);
|
||||
|
||||
ifp = if_get(rt->rt_ifidx);
|
||||
KASSERT(ifp != NULL);
|
||||
if (ifp == NULL)
|
||||
return;
|
||||
if (!ISSET(rt->rt_flags, RTF_STATIC|RTF_CACHED))
|
||||
rtdeletemsg(rt, ifp, ifp->if_rdomain);
|
||||
if_put(ifp);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: in_pcb.h,v 1.144 2023/12/15 00:24:56 bluhm Exp $ */
|
||||
/* $OpenBSD: in_pcb.h,v 1.145 2023/12/18 13:11:20 bluhm Exp $ */
|
||||
/* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */
|
||||
|
||||
/*
|
||||
@ -84,6 +84,38 @@
|
||||
* p inpcb_mtx pcb mutex
|
||||
*/
|
||||
|
||||
/*
|
||||
* The pcb table mutex guarantees that all inpcb are consistent and
|
||||
* that bind(2) and connect(2) create unique combinations of
|
||||
* laddr/faddr/lport/fport/rtalbleid. This mutex is used to protect
|
||||
* both address consistency and inpcb lookup during protocol input.
|
||||
* All writes to inp_[lf]addr take table mutex. A per socket lock is
|
||||
* needed, so that socket layer input have a consistent view at these
|
||||
* values.
|
||||
*
|
||||
* In soconnect() and sosend() pcb mutex cannot be used. They eventually
|
||||
* can call IP output which takes pf lock which is a sleeping lock.
|
||||
* Also connect(2) does a route lookup for source selection. There
|
||||
* route resolve happens, which creates a route, which sends a route
|
||||
* message, which needs route lock, which is a rw-lock.
|
||||
*
|
||||
* On the other hand a mutex should be used in protocol input. It
|
||||
* does not make sense to do a process switch per packet. Better spin
|
||||
* until the packet can be processed.
|
||||
*
|
||||
* So there are three locks. Table mutex is for writing inp_[lf]addr/port
|
||||
* and lookup, socket rw-lock to separate sockets in system calls, and
|
||||
* pcb mutex to protect socket receive buffer. Changing inp_[lf]addr/port
|
||||
* takes both per socket rw-lock and global table mutex. Protocol
|
||||
* input only reads inp_[lf]addr/port during lookup and is safe. System
|
||||
* call only reads when holding socket rw-lock and is safe. The socket
|
||||
* layer needs pcb mutex only in soreceive().
|
||||
*
|
||||
* Function pru_lock() grabs the pcb mutex and its existence indicates
|
||||
* that a protocol is MP safe. Otherwise the exclusive net lock is
|
||||
* used.
|
||||
*/
|
||||
|
||||
struct pf_state_key;
|
||||
|
||||
union inpaddru {
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: protosw.h,v 1.62 2023/05/18 09:59:44 mvs Exp $ */
|
||||
/* $OpenBSD: protosw.h,v 1.63 2023/12/18 13:11:20 bluhm Exp $ */
|
||||
/* $NetBSD: protosw.h,v 1.10 1996/04/09 20:55:32 cgd Exp $ */
|
||||
|
||||
/*-
|
||||
@ -284,13 +284,15 @@ pru_detach(struct socket *so)
|
||||
static inline void
|
||||
pru_lock(struct socket *so)
|
||||
{
|
||||
(*so->so_proto->pr_usrreqs->pru_lock)(so);
|
||||
if (so->so_proto->pr_usrreqs->pru_lock)
|
||||
(*so->so_proto->pr_usrreqs->pru_lock)(so);
|
||||
}
|
||||
|
||||
static inline void
|
||||
pru_unlock(struct socket *so)
|
||||
{
|
||||
(*so->so_proto->pr_usrreqs->pru_unlock)(so);
|
||||
if (so->so_proto->pr_usrreqs->pru_unlock)
|
||||
(*so->so_proto->pr_usrreqs->pru_unlock)(so);
|
||||
}
|
||||
|
||||
static inline int
|
||||
|
@ -137,6 +137,51 @@ than as a named global or channel request to allow pings with very
|
||||
short packet lengths, which would not be possible with other
|
||||
approaches.
|
||||
|
||||
1.9 transport: strict key exchange extension
|
||||
|
||||
OpenSSH supports a number of transport-layer hardening measures under
|
||||
a "strict KEX" feature. This feature is signalled similarly to the
|
||||
RFC8308 ext-info feature: by including a additional algorithm in the
|
||||
initiial SSH2_MSG_KEXINIT kex_algorithms field. The client may append
|
||||
"kex-strict-c-v00@openssh.com" to its kex_algorithms and the server
|
||||
may append "kex-strict-s-v00@openssh.com". These pseudo-algorithms
|
||||
are only valid in the initial SSH2_MSG_KEXINIT and MUST be ignored
|
||||
if they are present in subsequent SSH2_MSG_KEXINIT packets.
|
||||
|
||||
When an endpoint that supports this extension observes this algorithm
|
||||
name in a peer's KEXINIT packet, it MUST make the following changes to
|
||||
the the protocol:
|
||||
|
||||
a) During initial KEX, terminate the connection if any unexpected or
|
||||
out-of-sequence packet is received. This includes terminating the
|
||||
connection if the first packet received is not SSH2_MSG_KEXINIT.
|
||||
Unexpected packets for the purpose of strict KEX include messages
|
||||
that are otherwise valid at any time during the connection such as
|
||||
SSH2_MSG_DEBUG and SSH2_MSG_IGNORE.
|
||||
b) After sending or receiving a SSH2_MSG_NEWKEYS message, reset the
|
||||
packet sequence number to zero. This behaviour persists for the
|
||||
duration of the connection (i.e. not just the first
|
||||
SSH2_MSG_NEWKEYS).
|
||||
|
||||
1.10 transport: SSH2_MSG_EXT_INFO during user authentication
|
||||
|
||||
This protocol extension allows the SSH2_MSG_EXT_INFO to be sent
|
||||
during user authentication. RFC8308 does allow a second
|
||||
SSH2_MSG_EXT_INFO notification, but it may only be sent at the end
|
||||
of user authentication and this is too late to signal per-user
|
||||
server signature algorithms.
|
||||
|
||||
Support for receiving the SSH2_MSG_EXT_INFO message during user
|
||||
authentication is signalled by the client including a
|
||||
"ext-info-in-auth@openssh.com" key via its initial SSH2_MSG_EXT_INFO
|
||||
set after the SSH2_MSG_NEWKEYS message.
|
||||
|
||||
A server that supports this extension MAY send a second
|
||||
SSH2_MSG_EXT_INFO message any time after the client's first
|
||||
SSH2_MSG_USERAUTH_REQUEST, regardless of whether it succeed or fails.
|
||||
The client SHOULD be prepared to update the server-sig-algs that
|
||||
it received during an earlier SSH2_MSG_EXT_INFO with the later one.
|
||||
|
||||
2. Connection protocol changes
|
||||
|
||||
2.1. connection: Channel write close extension "eow@openssh.com"
|
||||
@ -745,4 +790,4 @@ master instance and later clients.
|
||||
OpenSSH extends the usual agent protocol. These changes are documented
|
||||
in the PROTOCOL.agent file.
|
||||
|
||||
$OpenBSD: PROTOCOL,v 1.49 2023/08/28 03:28:43 djm Exp $
|
||||
$OpenBSD: PROTOCOL,v 1.51 2023/12/18 14:45:49 djm Exp $
|
||||
|
@ -81,4 +81,35 @@ the constraint is:
|
||||
|
||||
This option is only valid for XMSS keys.
|
||||
|
||||
$OpenBSD: PROTOCOL.agent,v 1.20 2023/10/03 23:56:10 djm Exp $
|
||||
3. associated-certs-v00@openssh.com key constraint extension
|
||||
|
||||
The key constraint extension allows certificates to be associated
|
||||
with private keys as they are loaded from a PKCS#11 token.
|
||||
|
||||
byte SSH_AGENT_CONSTRAIN_EXTENSION (0xff)
|
||||
string associated-certs-v00@openssh.com
|
||||
bool certs_only
|
||||
string certsblob
|
||||
|
||||
Where "certsblob" constists of one or more certificates encoded as public
|
||||
key blobs:
|
||||
|
||||
string[] certificates
|
||||
|
||||
This extension is only valid for SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED
|
||||
requests. When an agent receives this extension, it will attempt to match
|
||||
each certificate in the request with a corresponding private key loaded
|
||||
from the requested PKCS#11 token. When a matching key is found, the
|
||||
agent will graft the certificate contents to the token-hosted private key
|
||||
and store the result for subsequent use by regular agent operations.
|
||||
|
||||
If the "certs_only" flag is set, then this extension will cause ONLY
|
||||
the resultant certificates to be loaded to the agent. The default
|
||||
behaviour is to load the PKCS#11-hosted private key as well as the
|
||||
resultant certificate.
|
||||
|
||||
A SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED will return SSH_AGENT_SUCCESS
|
||||
if any key (plain private or certificate) was successfully loaded, or
|
||||
SSH_AGENT_FAILURE if no key was loaded.
|
||||
|
||||
$OpenBSD: PROTOCOL.agent,v 1.21 2023/12/18 14:46:56 djm Exp $
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth2.c,v 1.167 2023/08/28 09:48:11 djm Exp $ */
|
||||
/* $OpenBSD: auth2.c,v 1.168 2023/12/18 14:45:49 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -55,6 +55,7 @@
|
||||
#include "monitor_wrap.h"
|
||||
#include "ssherr.h"
|
||||
#include "digest.h"
|
||||
#include "kex.h"
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
@ -162,6 +163,8 @@ do_authentication2(struct ssh *ssh)
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
|
||||
ssh_dispatch_init(ssh, &dispatch_protocol_error);
|
||||
if (ssh->kex->ext_info_c)
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_input_ext_info);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_REQUEST, &input_service_request);
|
||||
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt->success);
|
||||
ssh->authctxt = NULL;
|
||||
@ -201,6 +204,7 @@ input_service_request(int type, u_int32_t seq, struct ssh *ssh)
|
||||
debug("bad service request %s", service);
|
||||
ssh_packet_disconnect(ssh, "bad service request %s", service);
|
||||
}
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &dispatch_protocol_error);
|
||||
r = 0;
|
||||
out:
|
||||
free(service);
|
||||
@ -296,6 +300,8 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
|
||||
if (use_privsep)
|
||||
mm_inform_authserv(service, style);
|
||||
userauth_banner(ssh);
|
||||
if ((r = kex_server_update_ext_info(ssh)) != 0)
|
||||
fatal_fr(r, "kex_server_update_ext_info failed");
|
||||
if (auth2_setup_methods_lists(authctxt) != 0)
|
||||
ssh_packet_disconnect(ssh,
|
||||
"no authentication methods enabled");
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: authfd.c,v 1.133 2023/03/09 21:06:24 jcs Exp $ */
|
||||
/* $OpenBSD: authfd.c,v 1.134 2023/12/18 14:46:56 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -503,9 +503,10 @@ encode_dest_constraint(struct sshbuf *m, const struct dest_constraint *dc)
|
||||
}
|
||||
|
||||
static int
|
||||
encode_constraints(struct sshbuf *m, u_int life, u_int confirm, u_int maxsign,
|
||||
const char *provider, struct dest_constraint **dest_constraints,
|
||||
size_t ndest_constraints)
|
||||
encode_constraints(struct sshbuf *m, u_int life, u_int confirm,
|
||||
u_int maxsign, const char *provider,
|
||||
struct dest_constraint **dest_constraints, size_t ndest_constraints,
|
||||
int cert_only, struct sshkey **certs, size_t ncerts)
|
||||
{
|
||||
int r;
|
||||
struct sshbuf *b = NULL;
|
||||
@ -549,6 +550,27 @@ encode_constraints(struct sshbuf *m, u_int life, u_int confirm, u_int maxsign,
|
||||
"restrict-destination-v00@openssh.com")) != 0 ||
|
||||
(r = sshbuf_put_stringb(m, b)) != 0)
|
||||
goto out;
|
||||
sshbuf_free(b);
|
||||
b = NULL;
|
||||
}
|
||||
if (ncerts != 0) {
|
||||
if ((b = sshbuf_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < ncerts; i++) {
|
||||
if ((r = sshkey_puts(certs[i], b)) != 0)
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshbuf_put_u8(m,
|
||||
SSH_AGENT_CONSTRAIN_EXTENSION)) != 0 ||
|
||||
(r = sshbuf_put_cstring(m,
|
||||
"associated-certs-v00@openssh.com")) != 0 ||
|
||||
(r = sshbuf_put_u8(m, cert_only != 0)) != 0 ||
|
||||
(r = sshbuf_put_stringb(m, b)) != 0)
|
||||
goto out;
|
||||
sshbuf_free(b);
|
||||
b = NULL;
|
||||
}
|
||||
r = 0;
|
||||
out:
|
||||
@ -606,7 +628,7 @@ ssh_add_identity_constrained(int sock, struct sshkey *key,
|
||||
}
|
||||
if (constrained &&
|
||||
(r = encode_constraints(msg, life, confirm, maxsign,
|
||||
provider, dest_constraints, ndest_constraints)) != 0)
|
||||
provider, dest_constraints, ndest_constraints, 0, NULL, 0)) != 0)
|
||||
goto out;
|
||||
if ((r = ssh_request_reply_decode(sock, msg)) != 0)
|
||||
goto out;
|
||||
@ -661,10 +683,11 @@ ssh_remove_identity(int sock, const struct sshkey *key)
|
||||
int
|
||||
ssh_update_card(int sock, int add, const char *reader_id, const char *pin,
|
||||
u_int life, u_int confirm,
|
||||
struct dest_constraint **dest_constraints, size_t ndest_constraints)
|
||||
struct dest_constraint **dest_constraints, size_t ndest_constraints,
|
||||
int cert_only, struct sshkey **certs, size_t ncerts)
|
||||
{
|
||||
struct sshbuf *msg;
|
||||
int r, constrained = (life || confirm || dest_constraints);
|
||||
int r, constrained = (life || confirm || dest_constraints || certs);
|
||||
u_char type;
|
||||
|
||||
if (add) {
|
||||
@ -682,7 +705,8 @@ ssh_update_card(int sock, int add, const char *reader_id, const char *pin,
|
||||
goto out;
|
||||
if (constrained &&
|
||||
(r = encode_constraints(msg, life, confirm, 0, NULL,
|
||||
dest_constraints, ndest_constraints)) != 0)
|
||||
dest_constraints, ndest_constraints,
|
||||
cert_only, certs, ncerts)) != 0)
|
||||
goto out;
|
||||
if ((r = ssh_request_reply_decode(sock, msg)) != 0)
|
||||
goto out;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: authfd.h,v 1.51 2021/12/19 22:10:24 djm Exp $ */
|
||||
/* $OpenBSD: authfd.h,v 1.52 2023/12/18 14:46:56 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -56,7 +56,8 @@ int ssh_remove_identity(int sock, const struct sshkey *key);
|
||||
int ssh_update_card(int sock, int add, const char *reader_id,
|
||||
const char *pin, u_int life, u_int confirm,
|
||||
struct dest_constraint **dest_constraints,
|
||||
size_t ndest_constraints);
|
||||
size_t ndest_constraints,
|
||||
int cert_only, struct sshkey **certs, size_t ncerts);
|
||||
int ssh_remove_all_identities(int sock, int version);
|
||||
|
||||
int ssh_agent_sign(int sock, const struct sshkey *key,
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: channels.c,v 1.434 2023/11/15 22:51:49 djm Exp $ */
|
||||
/* $OpenBSD: channels.c,v 1.435 2023/12/18 14:47:20 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -3365,11 +3365,20 @@ channel_input_data(int type, u_int32_t seq, struct ssh *ssh)
|
||||
return 0;
|
||||
}
|
||||
if (win_len > c->local_window) {
|
||||
logit("channel %d: rcvd too much data %zu, win %u",
|
||||
c->self, win_len, c->local_window);
|
||||
return 0;
|
||||
c->local_window_exceeded += win_len - c->local_window;
|
||||
logit("channel %d: rcvd too much data %zu, win %u/%u "
|
||||
"(excess %u)", c->self, win_len, c->local_window,
|
||||
c->local_window_max, c->local_window_exceeded);
|
||||
c->local_window = 0;
|
||||
/* Allow 10% grace before bringing the hammer down */
|
||||
if (c->local_window_exceeded > (c->local_window_max / 10)) {
|
||||
ssh_packet_disconnect(ssh, "channel %d: peer ignored "
|
||||
"channel window", c->self);
|
||||
}
|
||||
} else {
|
||||
c->local_window -= win_len;
|
||||
c->local_window_exceeded = 0;
|
||||
}
|
||||
c->local_window -= win_len;
|
||||
|
||||
if (c->datagram) {
|
||||
if ((r = sshbuf_put_string(c->output, data, data_len)) != 0)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: channels.h,v 1.153 2023/11/15 22:51:49 djm Exp $ */
|
||||
/* $OpenBSD: channels.h,v 1.154 2023/12/18 14:47:20 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -167,6 +167,7 @@ struct Channel {
|
||||
u_int remote_window;
|
||||
u_int remote_maxpacket;
|
||||
u_int local_window;
|
||||
u_int local_window_exceeded;
|
||||
u_int local_window_max;
|
||||
u_int local_consumed;
|
||||
u_int local_maxpacket;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: kex.c,v 1.182 2023/10/11 04:46:29 djm Exp $ */
|
||||
/* $OpenBSD: kex.c,v 1.184 2023/12/18 14:45:49 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -60,7 +60,7 @@
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* prototype */
|
||||
static int kex_choose_conf(struct ssh *);
|
||||
static int kex_choose_conf(struct ssh *, uint32_t seq);
|
||||
static int kex_input_newkeys(int, u_int32_t, struct ssh *);
|
||||
|
||||
static const char * const proposal_names[PROPOSAL_MAX] = {
|
||||
@ -162,6 +162,18 @@ kex_names_valid(const char *names)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* returns non-zero if proposal contains any algorithm from algs */
|
||||
static int
|
||||
has_any_alg(const char *proposal, const char *algs)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
if ((cp = match_list(proposal, algs, NULL)) == NULL)
|
||||
return 0;
|
||||
free(cp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Concatenate algorithm names, avoiding duplicates in the process.
|
||||
* Caller must free returned string.
|
||||
@ -169,7 +181,7 @@ kex_names_valid(const char *names)
|
||||
char *
|
||||
kex_names_cat(const char *a, const char *b)
|
||||
{
|
||||
char *ret = NULL, *tmp = NULL, *cp, *p, *m;
|
||||
char *ret = NULL, *tmp = NULL, *cp, *p;
|
||||
size_t len;
|
||||
|
||||
if (a == NULL || *a == '\0')
|
||||
@ -186,10 +198,8 @@ kex_names_cat(const char *a, const char *b)
|
||||
}
|
||||
strlcpy(ret, a, len);
|
||||
for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) {
|
||||
if ((m = match_list(ret, p, NULL)) != NULL) {
|
||||
free(m);
|
||||
if (has_any_alg(ret, p))
|
||||
continue; /* Algorithm already present */
|
||||
}
|
||||
if (strlcat(ret, ",", len) >= len ||
|
||||
strlcat(ret, p, len) >= len) {
|
||||
free(tmp);
|
||||
@ -319,15 +329,23 @@ kex_proposal_populate_entries(struct ssh *ssh, char *prop[PROPOSAL_MAX],
|
||||
const char *defpropclient[PROPOSAL_MAX] = { KEX_CLIENT };
|
||||
const char **defprop = ssh->kex->server ? defpropserver : defpropclient;
|
||||
u_int i;
|
||||
char *cp;
|
||||
|
||||
if (prop == NULL)
|
||||
fatal_f("proposal missing");
|
||||
|
||||
/* Append EXT_INFO signalling to KexAlgorithms */
|
||||
if (kexalgos == NULL)
|
||||
kexalgos = defprop[PROPOSAL_KEX_ALGS];
|
||||
if ((cp = kex_names_cat(kexalgos, ssh->kex->server ?
|
||||
"ext-info-s,kex-strict-s-v00@openssh.com" :
|
||||
"ext-info-c,kex-strict-c-v00@openssh.com")) == NULL)
|
||||
fatal_f("kex_names_cat");
|
||||
|
||||
for (i = 0; i < PROPOSAL_MAX; i++) {
|
||||
switch(i) {
|
||||
case PROPOSAL_KEX_ALGS:
|
||||
prop[i] = compat_kex_proposal(ssh,
|
||||
kexalgos ? kexalgos : defprop[i]);
|
||||
prop[i] = compat_kex_proposal(ssh, cp);
|
||||
break;
|
||||
case PROPOSAL_ENC_ALGS_CTOS:
|
||||
case PROPOSAL_ENC_ALGS_STOC:
|
||||
@ -348,6 +366,7 @@ kex_proposal_populate_entries(struct ssh *ssh, char *prop[PROPOSAL_MAX],
|
||||
prop[i] = xstrdup(defprop[i]);
|
||||
}
|
||||
}
|
||||
free(cp);
|
||||
}
|
||||
|
||||
void
|
||||
@ -451,7 +470,12 @@ kex_protocol_error(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
int r;
|
||||
|
||||
error("kex protocol error: type %d seq %u", type, seq);
|
||||
/* If in strict mode, any unexpected message is an error */
|
||||
if ((ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) {
|
||||
ssh_packet_disconnect(ssh, "strict KEX violation: "
|
||||
"unexpected packet type %u (seqnr %u)", type, seq);
|
||||
}
|
||||
error_f("type %u seq %u", type, seq);
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, seq)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
@ -466,36 +490,138 @@ kex_reset_dispatch(struct ssh *ssh)
|
||||
SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
|
||||
}
|
||||
|
||||
void
|
||||
kex_set_server_sig_algs(struct ssh *ssh, const char *allowed_algs)
|
||||
{
|
||||
char *alg, *oalgs, *algs, *sigalgs;
|
||||
const char *sigalg;
|
||||
|
||||
/*
|
||||
* NB. allowed algorithms may contain certificate algorithms that
|
||||
* map to a specific plain signature type, e.g.
|
||||
* rsa-sha2-512-cert-v01@openssh.com => rsa-sha2-512
|
||||
* We need to be careful here to match these, retain the mapping
|
||||
* and only add each signature algorithm once.
|
||||
*/
|
||||
if ((sigalgs = sshkey_alg_list(0, 1, 1, ',')) == NULL)
|
||||
fatal_f("sshkey_alg_list failed");
|
||||
oalgs = algs = xstrdup(allowed_algs);
|
||||
free(ssh->kex->server_sig_algs);
|
||||
ssh->kex->server_sig_algs = NULL;
|
||||
for ((alg = strsep(&algs, ",")); alg != NULL && *alg != '\0';
|
||||
(alg = strsep(&algs, ","))) {
|
||||
if ((sigalg = sshkey_sigalg_by_name(alg)) == NULL)
|
||||
continue;
|
||||
if (!has_any_alg(sigalg, sigalgs))
|
||||
continue;
|
||||
/* Don't add an algorithm twice. */
|
||||
if (ssh->kex->server_sig_algs != NULL &&
|
||||
has_any_alg(sigalg, ssh->kex->server_sig_algs))
|
||||
continue;
|
||||
xextendf(&ssh->kex->server_sig_algs, ",", "%s", sigalg);
|
||||
}
|
||||
free(oalgs);
|
||||
free(sigalgs);
|
||||
if (ssh->kex->server_sig_algs == NULL)
|
||||
ssh->kex->server_sig_algs = xstrdup("");
|
||||
}
|
||||
|
||||
static int
|
||||
kex_send_ext_info(struct ssh *ssh)
|
||||
kex_compose_ext_info_server(struct ssh *ssh, struct sshbuf *m)
|
||||
{
|
||||
int r;
|
||||
char *algs;
|
||||
|
||||
debug("Sending SSH2_MSG_EXT_INFO");
|
||||
if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL)
|
||||
if (ssh->kex->server_sig_algs == NULL &&
|
||||
(ssh->kex->server_sig_algs = sshkey_alg_list(0, 1, 1, ',')) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
/* XXX filter algs list by allowed pubkey/hostbased types */
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, 3)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, algs)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh,
|
||||
if ((r = sshbuf_put_u32(m, 3)) != 0 ||
|
||||
(r = sshbuf_put_cstring(m, "server-sig-algs")) != 0 ||
|
||||
(r = sshbuf_put_cstring(m, ssh->kex->server_sig_algs)) != 0 ||
|
||||
(r = sshbuf_put_cstring(m,
|
||||
"publickey-hostbound@openssh.com")) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, "0")) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, "ping@openssh.com")) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, "0")) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0) {
|
||||
(r = sshbuf_put_cstring(m, "0")) != 0 ||
|
||||
(r = sshbuf_put_cstring(m, "ping@openssh.com")) != 0 ||
|
||||
(r = sshbuf_put_cstring(m, "0")) != 0) {
|
||||
error_fr(r, "compose");
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
kex_compose_ext_info_client(struct ssh *ssh, struct sshbuf *m)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshbuf_put_u32(m, 1)) != 0 ||
|
||||
(r = sshbuf_put_cstring(m, "ext-info-in-auth@openssh.com")) != 0 ||
|
||||
(r = sshbuf_put_cstring(m, "0")) != 0) {
|
||||
error_fr(r, "compose");
|
||||
goto out;
|
||||
}
|
||||
/* success */
|
||||
r = 0;
|
||||
out:
|
||||
free(algs);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
kex_maybe_send_ext_info(struct ssh *ssh)
|
||||
{
|
||||
int r;
|
||||
struct sshbuf *m = NULL;
|
||||
|
||||
if ((ssh->kex->flags & KEX_INITIAL) == 0)
|
||||
return 0;
|
||||
if (!ssh->kex->ext_info_c && !ssh->kex->ext_info_s)
|
||||
return 0;
|
||||
|
||||
/* Compose EXT_INFO packet. */
|
||||
if ((m = sshbuf_new()) == NULL)
|
||||
fatal_f("sshbuf_new failed");
|
||||
if (ssh->kex->ext_info_c &&
|
||||
(r = kex_compose_ext_info_server(ssh, m)) != 0)
|
||||
goto fail;
|
||||
if (ssh->kex->ext_info_s &&
|
||||
(r = kex_compose_ext_info_client(ssh, m)) != 0)
|
||||
goto fail;
|
||||
|
||||
/* Send the actual KEX_INFO packet */
|
||||
debug("Sending SSH2_MSG_EXT_INFO");
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
|
||||
(r = sshpkt_putb(ssh, m)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0) {
|
||||
error_f("send EXT_INFO");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
fail:
|
||||
sshbuf_free(m);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
kex_server_update_ext_info(struct ssh *ssh)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((ssh->kex->flags & KEX_HAS_EXT_INFO_IN_AUTH) == 0)
|
||||
return 0;
|
||||
|
||||
debug_f("Sending SSH2_MSG_EXT_INFO");
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, 1)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, ssh->kex->server_sig_algs)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0) {
|
||||
error_f("send EXT_INFO");
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
kex_send_newkeys(struct ssh *ssh)
|
||||
{
|
||||
@ -507,9 +633,8 @@ kex_send_newkeys(struct ssh *ssh)
|
||||
return r;
|
||||
debug("SSH2_MSG_NEWKEYS sent");
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys);
|
||||
if (ssh->kex->ext_info_c && (ssh->kex->flags & KEX_INITIAL) != 0)
|
||||
if ((r = kex_send_ext_info(ssh)) != 0)
|
||||
return r;
|
||||
if ((r = kex_maybe_send_ext_info(ssh)) != 0)
|
||||
return r;
|
||||
debug("expecting SSH2_MSG_NEWKEYS");
|
||||
return 0;
|
||||
}
|
||||
@ -531,10 +656,61 @@ kex_ext_info_check_ver(struct kex *kex, const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
kex_ext_info_client_parse(struct ssh *ssh, const char *name,
|
||||
const u_char *value, size_t vlen)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* NB. some messages are only accepted in the initial EXT_INFO */
|
||||
if (strcmp(name, "server-sig-algs") == 0) {
|
||||
/* Ensure no \0 lurking in value */
|
||||
if (memchr(value, '\0', vlen) != NULL) {
|
||||
error_f("nul byte in %s", name);
|
||||
return SSH_ERR_INVALID_FORMAT;
|
||||
}
|
||||
debug_f("%s=<%s>", name, value);
|
||||
free(ssh->kex->server_sig_algs);
|
||||
ssh->kex->server_sig_algs = xstrdup((const char *)value);
|
||||
} else if (ssh->kex->ext_info_received == 1 &&
|
||||
strcmp(name, "publickey-hostbound@openssh.com") == 0) {
|
||||
if ((r = kex_ext_info_check_ver(ssh->kex, name, value, vlen,
|
||||
"0", KEX_HAS_PUBKEY_HOSTBOUND)) != 0) {
|
||||
return r;
|
||||
}
|
||||
} else if (ssh->kex->ext_info_received == 1 &&
|
||||
strcmp(name, "ping@openssh.com") == 0) {
|
||||
if ((r = kex_ext_info_check_ver(ssh->kex, name, value, vlen,
|
||||
"0", KEX_HAS_PING)) != 0) {
|
||||
return r;
|
||||
}
|
||||
} else
|
||||
debug_f("%s (unrecognised)", name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
kex_ext_info_server_parse(struct ssh *ssh, const char *name,
|
||||
const u_char *value, size_t vlen)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (strcmp(name, "ext-info-in-auth@openssh.com") == 0) {
|
||||
if ((r = kex_ext_info_check_ver(ssh->kex, name, value, vlen,
|
||||
"0", KEX_HAS_EXT_INFO_IN_AUTH)) != 0) {
|
||||
return r;
|
||||
}
|
||||
} else
|
||||
debug_f("%s (unrecognised)", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct kex *kex = ssh->kex;
|
||||
const int max_ext_info = kex->server ? 1 : 2;
|
||||
u_int32_t i, ninfo;
|
||||
char *name;
|
||||
u_char *val;
|
||||
@ -542,13 +718,17 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
|
||||
int r;
|
||||
|
||||
debug("SSH2_MSG_EXT_INFO received");
|
||||
if (++kex->ext_info_received > max_ext_info) {
|
||||
error("too many SSH2_MSG_EXT_INFO messages sent by peer");
|
||||
return dispatch_protocol_error(type, seq, ssh);
|
||||
}
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error);
|
||||
if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0)
|
||||
return r;
|
||||
if (ninfo >= 1024) {
|
||||
error("SSH2_MSG_EXT_INFO with too many entries, expected "
|
||||
"<=1024, received %u", ninfo);
|
||||
return SSH_ERR_INVALID_FORMAT;
|
||||
return dispatch_protocol_error(type, seq, ssh);
|
||||
}
|
||||
for (i = 0; i < ninfo; i++) {
|
||||
if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0)
|
||||
@ -557,34 +737,16 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
|
||||
free(name);
|
||||
return r;
|
||||
}
|
||||
if (strcmp(name, "server-sig-algs") == 0) {
|
||||
/* Ensure no \0 lurking in value */
|
||||
if (memchr(val, '\0', vlen) != NULL) {
|
||||
error_f("nul byte in %s", name);
|
||||
free(name);
|
||||
free(val);
|
||||
return SSH_ERR_INVALID_FORMAT;
|
||||
}
|
||||
debug_f("%s=<%s>", name, val);
|
||||
kex->server_sig_algs = val;
|
||||
val = NULL;
|
||||
} else if (strcmp(name,
|
||||
"publickey-hostbound@openssh.com") == 0) {
|
||||
if ((r = kex_ext_info_check_ver(kex, name, val, vlen,
|
||||
"0", KEX_HAS_PUBKEY_HOSTBOUND)) != 0) {
|
||||
free(name);
|
||||
free(val);
|
||||
debug3_f("extension %s", name);
|
||||
if (kex->server) {
|
||||
if ((r = kex_ext_info_server_parse(ssh, name,
|
||||
val, vlen)) != 0)
|
||||
return r;
|
||||
}
|
||||
} else if (strcmp(name, "ping@openssh.com") == 0) {
|
||||
if ((r = kex_ext_info_check_ver(kex, name, val, vlen,
|
||||
"0", KEX_HAS_PING)) != 0) {
|
||||
free(name);
|
||||
free(val);
|
||||
} else {
|
||||
if ((r = kex_ext_info_client_parse(ssh, name,
|
||||
val, vlen)) != 0)
|
||||
return r;
|
||||
}
|
||||
} else
|
||||
debug_f("%s (unrecognised)", name);
|
||||
}
|
||||
free(name);
|
||||
free(val);
|
||||
}
|
||||
@ -598,6 +760,8 @@ kex_input_newkeys(int type, u_int32_t seq, struct ssh *ssh)
|
||||
int r;
|
||||
|
||||
debug("SSH2_MSG_NEWKEYS received");
|
||||
if (kex->ext_info_c && (kex->flags & KEX_INITIAL) != 0)
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_input_ext_info);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
|
||||
if ((r = sshpkt_get_end(ssh)) != 0)
|
||||
@ -666,7 +830,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
|
||||
error_f("no kex");
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
}
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_protocol_error);
|
||||
ptr = sshpkt_ptr(ssh, &dlen);
|
||||
if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
|
||||
return r;
|
||||
@ -702,7 +866,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
|
||||
if (!(kex->flags & KEX_INIT_SENT))
|
||||
if ((r = kex_send_kexinit(ssh)) != 0)
|
||||
return r;
|
||||
if ((r = kex_choose_conf(ssh)) != 0)
|
||||
if ((r = kex_choose_conf(ssh, seq)) != 0)
|
||||
return r;
|
||||
|
||||
if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
|
||||
@ -964,20 +1128,14 @@ proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* returns non-zero if proposal contains any algorithm from algs */
|
||||
static int
|
||||
has_any_alg(const char *proposal, const char *algs)
|
||||
kexalgs_contains(char **peer, const char *ext)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
if ((cp = match_list(proposal, algs, NULL)) == NULL)
|
||||
return 0;
|
||||
free(cp);
|
||||
return 1;
|
||||
return has_any_alg(peer[PROPOSAL_KEX_ALGS], ext);
|
||||
}
|
||||
|
||||
static int
|
||||
kex_choose_conf(struct ssh *ssh)
|
||||
kex_choose_conf(struct ssh *ssh, uint32_t seq)
|
||||
{
|
||||
struct kex *kex = ssh->kex;
|
||||
struct newkeys *newkeys;
|
||||
@ -1002,13 +1160,24 @@ kex_choose_conf(struct ssh *ssh)
|
||||
sprop=peer;
|
||||
}
|
||||
|
||||
/* Check whether client supports ext_info_c */
|
||||
if (kex->server && (kex->flags & KEX_INITIAL)) {
|
||||
char *ext;
|
||||
|
||||
ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL);
|
||||
kex->ext_info_c = (ext != NULL);
|
||||
free(ext);
|
||||
/* Check whether peer supports ext_info/kex_strict */
|
||||
if ((kex->flags & KEX_INITIAL) != 0) {
|
||||
if (kex->server) {
|
||||
kex->ext_info_c = kexalgs_contains(peer, "ext-info-c");
|
||||
kex->kex_strict = kexalgs_contains(peer,
|
||||
"kex-strict-c-v00@openssh.com");
|
||||
} else {
|
||||
kex->ext_info_s = kexalgs_contains(peer, "ext-info-s");
|
||||
kex->kex_strict = kexalgs_contains(peer,
|
||||
"kex-strict-s-v00@openssh.com");
|
||||
}
|
||||
if (kex->kex_strict) {
|
||||
debug3_f("will use strict KEX ordering");
|
||||
if (seq != 0)
|
||||
ssh_packet_disconnect(ssh,
|
||||
"strict KEX violation: "
|
||||
"KEXINIT was not the first packet");
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether client supports rsa-sha2 algorithms */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: kex.h,v 1.119 2023/08/28 03:28:43 djm Exp $ */
|
||||
/* $OpenBSD: kex.h,v 1.121 2023/12/18 14:45:49 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
@ -105,6 +105,7 @@ enum kex_exchange {
|
||||
#define KEX_RSA_SHA2_256_SUPPORTED 0x0008 /* only set in server for now */
|
||||
#define KEX_RSA_SHA2_512_SUPPORTED 0x0010 /* only set in server for now */
|
||||
#define KEX_HAS_PING 0x0020
|
||||
#define KEX_HAS_EXT_INFO_IN_AUTH 0x0040
|
||||
|
||||
struct sshenc {
|
||||
char *name;
|
||||
@ -142,6 +143,9 @@ struct kex {
|
||||
u_int kex_type;
|
||||
char *server_sig_algs;
|
||||
int ext_info_c;
|
||||
int ext_info_s;
|
||||
int kex_strict;
|
||||
int ext_info_received;
|
||||
struct sshbuf *my;
|
||||
struct sshbuf *peer;
|
||||
struct sshbuf *client_version;
|
||||
@ -201,6 +205,8 @@ int kex_protocol_error(int, u_int32_t, struct ssh *);
|
||||
int kex_derive_keys(struct ssh *, u_char *, u_int, const struct sshbuf *);
|
||||
int kex_send_newkeys(struct ssh *);
|
||||
int kex_start_rekex(struct ssh *);
|
||||
int kex_server_update_ext_info(struct ssh *);
|
||||
void kex_set_server_sig_algs(struct ssh *, const char *);
|
||||
|
||||
int kexgex_client(struct ssh *);
|
||||
int kexgex_server(struct ssh *);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: monitor_wrap.c,v 1.128 2023/03/31 00:44:29 dtucker Exp $ */
|
||||
/* $OpenBSD: monitor_wrap.c,v 1.129 2023/12/18 14:45:49 djm Exp $ */
|
||||
/*
|
||||
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||
* Copyright 2002 Markus Friedl <markus@openbsd.org>
|
||||
@ -327,8 +327,8 @@ out:
|
||||
log_verbose_add(options.log_verbose[i]);
|
||||
process_permitopen(ssh, &options);
|
||||
process_channel_timeouts(ssh, &options);
|
||||
kex_set_server_sig_algs(ssh, options.pubkey_accepted_algos);
|
||||
free(newopts);
|
||||
|
||||
sshbuf_free(m);
|
||||
|
||||
return (pw);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: packet.c,v 1.312 2023/08/28 03:31:16 djm Exp $ */
|
||||
/* $OpenBSD: packet.c,v 1.313 2023/12/18 14:45:17 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -1187,8 +1187,13 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
|
||||
sshbuf_dump(state->output, stderr);
|
||||
#endif
|
||||
/* increment sequence number for outgoing packets */
|
||||
if (++state->p_send.seqnr == 0)
|
||||
if (++state->p_send.seqnr == 0) {
|
||||
if ((ssh->kex->flags & KEX_INITIAL) != 0) {
|
||||
ssh_packet_disconnect(ssh, "outgoing sequence number "
|
||||
"wrapped during initial key exchange");
|
||||
}
|
||||
logit("outgoing seqnr wraps around");
|
||||
}
|
||||
if (++state->p_send.packets == 0)
|
||||
if (!(ssh->compat & SSH_BUG_NOREKEY))
|
||||
return SSH_ERR_NEED_REKEY;
|
||||
@ -1196,6 +1201,11 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
|
||||
state->p_send.bytes += len;
|
||||
sshbuf_reset(state->outgoing_packet);
|
||||
|
||||
if (type == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) {
|
||||
debug_f("resetting send seqnr %u", state->p_send.seqnr);
|
||||
state->p_send.seqnr = 0;
|
||||
}
|
||||
|
||||
if (type == SSH2_MSG_NEWKEYS)
|
||||
r = ssh_set_newkeys(ssh, MODE_OUT);
|
||||
else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side)
|
||||
@ -1324,8 +1334,7 @@ ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
/* Stay in the loop until we have received a complete packet. */
|
||||
for (;;) {
|
||||
/* Try to read a packet from the buffer. */
|
||||
r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p);
|
||||
if (r != 0)
|
||||
if ((r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p)) != 0)
|
||||
break;
|
||||
/* If we got a packet, return it. */
|
||||
if (*typep != SSH_MSG_NONE)
|
||||
@ -1395,29 +1404,6 @@ ssh_packet_read(struct ssh *ssh)
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
* Waits until a packet has been received, verifies that its type matches
|
||||
* that given, and gives a fatal error and exits if there is a mismatch.
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_packet_read_expect(struct ssh *ssh, u_int expected_type)
|
||||
{
|
||||
int r;
|
||||
u_char type;
|
||||
|
||||
if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0)
|
||||
return r;
|
||||
if (type != expected_type) {
|
||||
if ((r = sshpkt_disconnect(ssh,
|
||||
"Protocol error: expected packet type %d, got %d",
|
||||
expected_type, type)) != 0)
|
||||
return r;
|
||||
return SSH_ERR_PROTOCOL_ERROR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
{
|
||||
@ -1608,10 +1594,16 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (seqnr_p != NULL)
|
||||
*seqnr_p = state->p_read.seqnr;
|
||||
if (++state->p_read.seqnr == 0)
|
||||
if (++state->p_read.seqnr == 0) {
|
||||
if ((ssh->kex->flags & KEX_INITIAL) != 0) {
|
||||
ssh_packet_disconnect(ssh, "incoming sequence number "
|
||||
"wrapped during initial key exchange");
|
||||
}
|
||||
logit("incoming seqnr wraps around");
|
||||
}
|
||||
if (++state->p_read.packets == 0)
|
||||
if (!(ssh->compat & SSH_BUG_NOREKEY))
|
||||
return SSH_ERR_NEED_REKEY;
|
||||
@ -1677,6 +1669,10 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
#endif
|
||||
/* reset for next packet */
|
||||
state->packlen = 0;
|
||||
if (*typep == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) {
|
||||
debug_f("resetting read seqnr %u", state->p_read.seqnr);
|
||||
state->p_read.seqnr = 0;
|
||||
}
|
||||
|
||||
if ((r = ssh_packet_check_rekey(ssh)) != 0)
|
||||
return r;
|
||||
@ -1699,10 +1695,39 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
r = ssh_packet_read_poll2(ssh, typep, seqnr_p);
|
||||
if (r != 0)
|
||||
return r;
|
||||
if (*typep) {
|
||||
state->keep_alive_timeouts = 0;
|
||||
DBG(debug("received packet type %d", *typep));
|
||||
if (*typep == 0) {
|
||||
/* no message ready */
|
||||
return 0;
|
||||
}
|
||||
state->keep_alive_timeouts = 0;
|
||||
DBG(debug("received packet type %d", *typep));
|
||||
|
||||
/* Always process disconnect messages */
|
||||
if (*typep == SSH2_MSG_DISCONNECT) {
|
||||
if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
|
||||
return r;
|
||||
/* Ignore normal client exit notifications */
|
||||
do_log2(ssh->state->server_side &&
|
||||
reason == SSH2_DISCONNECT_BY_APPLICATION ?
|
||||
SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
|
||||
"Received disconnect from %s port %d:"
|
||||
"%u: %.400s", ssh_remote_ipaddr(ssh),
|
||||
ssh_remote_port(ssh), reason, msg);
|
||||
free(msg);
|
||||
return SSH_ERR_DISCONNECTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not implicitly handle any messages here during initial
|
||||
* KEX when in strict mode. They will be need to be allowed
|
||||
* explicitly by the KEX dispatch table or they will generate
|
||||
* protocol errors.
|
||||
*/
|
||||
if (ssh->kex != NULL &&
|
||||
(ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict)
|
||||
return 0;
|
||||
/* Implicitly handle transport-level messages */
|
||||
switch (*typep) {
|
||||
case SSH2_MSG_IGNORE:
|
||||
debug3("Received SSH2_MSG_IGNORE");
|
||||
@ -1717,19 +1742,6 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
debug("Remote: %.900s", msg);
|
||||
free(msg);
|
||||
break;
|
||||
case SSH2_MSG_DISCONNECT:
|
||||
if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
|
||||
return r;
|
||||
/* Ignore normal client exit notifications */
|
||||
do_log2(ssh->state->server_side &&
|
||||
reason == SSH2_DISCONNECT_BY_APPLICATION ?
|
||||
SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
|
||||
"Received disconnect from %s port %d:"
|
||||
"%u: %.400s", ssh_remote_ipaddr(ssh),
|
||||
ssh_remote_port(ssh), reason, msg);
|
||||
free(msg);
|
||||
return SSH_ERR_DISCONNECTED;
|
||||
case SSH2_MSG_UNIMPLEMENTED:
|
||||
if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0)
|
||||
return r;
|
||||
@ -2219,6 +2231,7 @@ kex_to_blob(struct sshbuf *m, struct kex *kex)
|
||||
(r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, kex->hostkey_nid)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, kex->kex_type)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, kex->kex_strict)) != 0 ||
|
||||
(r = sshbuf_put_stringb(m, kex->my)) != 0 ||
|
||||
(r = sshbuf_put_stringb(m, kex->peer)) != 0 ||
|
||||
(r = sshbuf_put_stringb(m, kex->client_version)) != 0 ||
|
||||
@ -2381,6 +2394,7 @@ kex_from_blob(struct sshbuf *m, struct kex **kexp)
|
||||
(r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_nid)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &kex->kex_type)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &kex->kex_strict)) != 0 ||
|
||||
(r = sshbuf_get_stringb(m, kex->my)) != 0 ||
|
||||
(r = sshbuf_get_stringb(m, kex->peer)) != 0 ||
|
||||
(r = sshbuf_get_stringb(m, kex->client_version)) != 0 ||
|
||||
@ -2705,6 +2719,7 @@ sshpkt_disconnect(struct ssh *ssh, const char *fmt,...)
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
debug2_f("sending SSH2_MSG_DISCONNECT: %s", buf);
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, buf)) != 0 ||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: packet.h,v 1.95 2023/08/28 03:31:16 djm Exp $ */
|
||||
/* $OpenBSD: packet.h,v 1.96 2023/12/18 14:45:17 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -118,7 +118,6 @@ int ssh_packet_send2_wrapped(struct ssh *);
|
||||
int ssh_packet_send2(struct ssh *);
|
||||
|
||||
int ssh_packet_read(struct ssh *);
|
||||
int ssh_packet_read_expect(struct ssh *, u_int type);
|
||||
int ssh_packet_read_poll(struct ssh *);
|
||||
int ssh_packet_read_poll2(struct ssh *, u_char *, u_int32_t *seqnr_p);
|
||||
int ssh_packet_process_incoming(struct ssh *, const char *buf, u_int len);
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: ssh-add.1,v 1.84 2022/02/04 02:49:17 dtucker Exp $
|
||||
.\" $OpenBSD: ssh-add.1,v 1.85 2023/12/18 14:46:56 djm Exp $
|
||||
.\"
|
||||
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -35,7 +35,7 @@
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd $Mdocdate: February 4 2022 $
|
||||
.Dd $Mdocdate: December 18 2023 $
|
||||
.Dt SSH-ADD 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -43,7 +43,7 @@
|
||||
.Nd adds private key identities to the OpenSSH authentication agent
|
||||
.Sh SYNOPSIS
|
||||
.Nm ssh-add
|
||||
.Op Fl cDdKkLlqvXx
|
||||
.Op Fl cCDdKkLlqvXx
|
||||
.Op Fl E Ar fingerprint_hash
|
||||
.Op Fl H Ar hostkey_file
|
||||
.Op Fl h Ar destination_constraint
|
||||
@ -52,6 +52,8 @@
|
||||
.Op Ar
|
||||
.Nm ssh-add
|
||||
.Fl s Ar pkcs11
|
||||
.Op Fl vC
|
||||
.Op Ar certificate ...
|
||||
.Nm ssh-add
|
||||
.Fl e Ar pkcs11
|
||||
.Nm ssh-add
|
||||
@ -100,6 +102,9 @@ Confirmation is performed by
|
||||
Successful confirmation is signaled by a zero exit status from
|
||||
.Xr ssh-askpass 1 ,
|
||||
rather than text entered into the requester.
|
||||
.It Fl C
|
||||
When loading keys into or deleting keys from the agent, process
|
||||
certificates only and skip plain keys.
|
||||
.It Fl D
|
||||
Deletes all identities from the agent.
|
||||
.It Fl d
|
||||
@ -228,6 +233,9 @@ internal USB HID support.
|
||||
.It Fl s Ar pkcs11
|
||||
Add keys provided by the PKCS#11 shared library
|
||||
.Ar pkcs11 .
|
||||
Certificate files may optionally be listed as command-line arguments.
|
||||
If these are present, then they will be loaded into the agent using any
|
||||
corresponding private keys loaded from the PKCS#11 token.
|
||||
.It Fl T Ar pubkey ...
|
||||
Tests whether the private keys that correspond to the specified
|
||||
.Ar pubkey
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh-add.c,v 1.168 2023/07/06 22:17:59 dtucker Exp $ */
|
||||
/* $OpenBSD: ssh-add.c,v 1.169 2023/12/18 14:46:56 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -124,7 +124,7 @@ delete_one(int agent_fd, const struct sshkey *key, const char *comment,
|
||||
}
|
||||
|
||||
static int
|
||||
delete_stdin(int agent_fd, int qflag)
|
||||
delete_stdin(int agent_fd, int qflag, int key_only, int cert_only)
|
||||
{
|
||||
char *line = NULL, *cp;
|
||||
size_t linesize = 0;
|
||||
@ -145,8 +145,13 @@ delete_stdin(int agent_fd, int qflag)
|
||||
error_r(r, "(stdin):%d: invalid key", lnum);
|
||||
continue;
|
||||
}
|
||||
if (delete_one(agent_fd, key, cp, "(stdin)", qflag) == 0)
|
||||
ret = 0;
|
||||
if ((!key_only && !cert_only) ||
|
||||
(key_only && !sshkey_is_cert(key)) ||
|
||||
(cert_only && sshkey_is_cert(key))) {
|
||||
if (delete_one(agent_fd, key, cp,
|
||||
"(stdin)", qflag) == 0)
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
sshkey_free(key);
|
||||
free(line);
|
||||
@ -154,21 +159,26 @@ delete_stdin(int agent_fd, int qflag)
|
||||
}
|
||||
|
||||
static int
|
||||
delete_file(int agent_fd, const char *filename, int key_only, int qflag)
|
||||
delete_file(int agent_fd, const char *filename, int key_only,
|
||||
int cert_only, int qflag)
|
||||
{
|
||||
struct sshkey *public, *cert = NULL;
|
||||
char *certpath = NULL, *comment = NULL;
|
||||
int r, ret = -1;
|
||||
|
||||
if (strcmp(filename, "-") == 0)
|
||||
return delete_stdin(agent_fd, qflag);
|
||||
return delete_stdin(agent_fd, qflag, key_only, cert_only);
|
||||
|
||||
if ((r = sshkey_load_public(filename, &public, &comment)) != 0) {
|
||||
printf("Bad key file %s: %s\n", filename, ssh_err(r));
|
||||
return -1;
|
||||
}
|
||||
if (delete_one(agent_fd, public, comment, filename, qflag) == 0)
|
||||
ret = 0;
|
||||
if ((!key_only && !cert_only) ||
|
||||
(key_only && !sshkey_is_cert(public)) ||
|
||||
(cert_only && sshkey_is_cert(public))) {
|
||||
if (delete_one(agent_fd, public, comment, filename, qflag) == 0)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (key_only)
|
||||
goto out;
|
||||
@ -224,8 +234,9 @@ delete_all(int agent_fd, int qflag)
|
||||
}
|
||||
|
||||
static int
|
||||
add_file(int agent_fd, const char *filename, int key_only, int qflag,
|
||||
const char *skprovider, struct dest_constraint **dest_constraints,
|
||||
add_file(int agent_fd, const char *filename, int key_only, int cert_only,
|
||||
int qflag, const char *skprovider,
|
||||
struct dest_constraint **dest_constraints,
|
||||
size_t ndest_constraints)
|
||||
{
|
||||
struct sshkey *private, *cert;
|
||||
@ -354,7 +365,8 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag,
|
||||
skprovider = NULL;
|
||||
}
|
||||
|
||||
if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
|
||||
if (!cert_only &&
|
||||
(r = ssh_add_identity_constrained(agent_fd, private, comment,
|
||||
lifetime, confirm, maxsign, skprovider,
|
||||
dest_constraints, ndest_constraints)) == 0) {
|
||||
ret = 0;
|
||||
@ -383,7 +395,8 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag,
|
||||
xasprintf(&certpath, "%s-cert.pub", filename);
|
||||
if ((r = sshkey_load_public(certpath, &cert, NULL)) != 0) {
|
||||
if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT)
|
||||
error_r(r, "Failed to load certificate \"%s\"", certpath);
|
||||
error_r(r, "Failed to load certificate \"%s\"",
|
||||
certpath);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -438,11 +451,16 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag,
|
||||
|
||||
static int
|
||||
update_card(int agent_fd, int add, const char *id, int qflag,
|
||||
struct dest_constraint **dest_constraints, size_t ndest_constraints)
|
||||
int key_only, int cert_only,
|
||||
struct dest_constraint **dest_constraints, size_t ndest_constraints,
|
||||
struct sshkey **certs, size_t ncerts)
|
||||
{
|
||||
char *pin = NULL;
|
||||
int r, ret = -1;
|
||||
|
||||
if (key_only)
|
||||
ncerts = 0;
|
||||
|
||||
if (add) {
|
||||
if ((pin = read_passphrase("Enter passphrase for PKCS#11: ",
|
||||
RP_ALLOW_STDIN)) == NULL)
|
||||
@ -450,7 +468,8 @@ update_card(int agent_fd, int add, const char *id, int qflag,
|
||||
}
|
||||
|
||||
if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : pin,
|
||||
lifetime, confirm, dest_constraints, ndest_constraints)) == 0) {
|
||||
lifetime, confirm, dest_constraints, ndest_constraints,
|
||||
cert_only, certs, ncerts)) == 0) {
|
||||
ret = 0;
|
||||
if (!qflag) {
|
||||
fprintf(stderr, "Card %s: %s\n",
|
||||
@ -626,16 +645,17 @@ load_resident_keys(int agent_fd, const char *skprovider, int qflag,
|
||||
}
|
||||
|
||||
static int
|
||||
do_file(int agent_fd, int deleting, int key_only, char *file, int qflag,
|
||||
const char *skprovider, struct dest_constraint **dest_constraints,
|
||||
size_t ndest_constraints)
|
||||
do_file(int agent_fd, int deleting, int key_only, int cert_only,
|
||||
char *file, int qflag, const char *skprovider,
|
||||
struct dest_constraint **dest_constraints, size_t ndest_constraints)
|
||||
{
|
||||
if (deleting) {
|
||||
if (delete_file(agent_fd, file, key_only, qflag) == -1)
|
||||
if (delete_file(agent_fd, file, key_only,
|
||||
cert_only, qflag) == -1)
|
||||
return -1;
|
||||
} else {
|
||||
if (add_file(agent_fd, file, key_only, qflag, skprovider,
|
||||
dest_constraints, ndest_constraints) == -1)
|
||||
if (add_file(agent_fd, file, key_only, cert_only, qflag,
|
||||
skprovider, dest_constraints, ndest_constraints) == -1)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@ -783,12 +803,14 @@ main(int argc, char **argv)
|
||||
int agent_fd;
|
||||
char *pkcs11provider = NULL, *skprovider = NULL;
|
||||
char **dest_constraint_strings = NULL, **hostkey_files = NULL;
|
||||
int r, i, ch, deleting = 0, ret = 0, key_only = 0, do_download = 0;
|
||||
int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0;
|
||||
int r, i, ch, deleting = 0, ret = 0, key_only = 0, cert_only = 0;
|
||||
int do_download = 0, xflag = 0, lflag = 0, Dflag = 0;
|
||||
int qflag = 0, Tflag = 0;
|
||||
SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
|
||||
LogLevel log_level = SYSLOG_LEVEL_INFO;
|
||||
struct sshkey *k, **certs = NULL;
|
||||
struct dest_constraint **dest_constraints = NULL;
|
||||
size_t ndest_constraints = 0;
|
||||
size_t ndest_constraints = 0i, ncerts = 0;
|
||||
|
||||
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
|
||||
sanitise_stdfd();
|
||||
@ -815,7 +837,7 @@ main(int argc, char **argv)
|
||||
|
||||
skprovider = getenv("SSH_SK_PROVIDER");
|
||||
|
||||
while ((ch = getopt(argc, argv, "vkKlLcdDTxXE:e:h:H:M:m:qs:S:t:")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "vkKlLCcdDTxXE:e:h:H:M:m:qs:S:t:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'v':
|
||||
if (log_level == SYSLOG_LEVEL_INFO)
|
||||
@ -837,6 +859,9 @@ main(int argc, char **argv)
|
||||
case 'k':
|
||||
key_only = 1;
|
||||
break;
|
||||
case 'C':
|
||||
cert_only = 1;
|
||||
break;
|
||||
case 'K':
|
||||
do_download = 1;
|
||||
break;
|
||||
@ -952,8 +977,19 @@ main(int argc, char **argv)
|
||||
goto done;
|
||||
}
|
||||
if (pkcs11provider != NULL) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
if ((r = sshkey_load_public(argv[i], &k, NULL)) != 0)
|
||||
fatal_fr(r, "load certificate %s", argv[i]);
|
||||
certs = xrecallocarray(certs, ncerts, ncerts + 1,
|
||||
sizeof(*certs));
|
||||
debug2("%s: %s", argv[i], sshkey_ssh_name(k));
|
||||
certs[ncerts++] = k;
|
||||
}
|
||||
debug2_f("loaded %zu certificates", ncerts);
|
||||
if (update_card(agent_fd, !deleting, pkcs11provider,
|
||||
qflag, dest_constraints, ndest_constraints) == -1)
|
||||
qflag, key_only, cert_only,
|
||||
dest_constraints, ndest_constraints,
|
||||
certs, ncerts) == -1)
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
@ -983,8 +1019,8 @@ main(int argc, char **argv)
|
||||
default_files[i]);
|
||||
if (stat(buf, &st) == -1)
|
||||
continue;
|
||||
if (do_file(agent_fd, deleting, key_only, buf,
|
||||
qflag, skprovider,
|
||||
if (do_file(agent_fd, deleting, key_only, cert_only,
|
||||
buf, qflag, skprovider,
|
||||
dest_constraints, ndest_constraints) == -1)
|
||||
ret = 1;
|
||||
else
|
||||
@ -994,7 +1030,7 @@ main(int argc, char **argv)
|
||||
ret = 1;
|
||||
} else {
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (do_file(agent_fd, deleting, key_only,
|
||||
if (do_file(agent_fd, deleting, key_only, cert_only,
|
||||
argv[i], qflag, skprovider,
|
||||
dest_constraints, ndest_constraints) == -1)
|
||||
ret = 1;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh-agent.c,v 1.300 2023/07/19 13:56:33 djm Exp $ */
|
||||
/* $OpenBSD: ssh-agent.c,v 1.304 2023/12/18 15:58:56 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -92,6 +92,8 @@
|
||||
#define AGENT_MAX_SID_LEN 128
|
||||
/* Maximum number of destination constraints to accept on a key */
|
||||
#define AGENT_MAX_DEST_CONSTRAINTS 1024
|
||||
/* Maximum number of associated certificate constraints to accept on a key */
|
||||
#define AGENT_MAX_EXT_CERTS 1024
|
||||
|
||||
/* XXX store hostkey_sid in a refcounted tree */
|
||||
|
||||
@ -115,6 +117,7 @@ typedef struct socket_entry {
|
||||
struct sshbuf *request;
|
||||
size_t nsession_ids;
|
||||
struct hostkey_sid *session_ids;
|
||||
int session_bind_attempted;
|
||||
} SocketEntry;
|
||||
|
||||
u_int sockets_alloc = 0;
|
||||
@ -234,6 +237,91 @@ free_dest_constraints(struct dest_constraint *dcs, size_t ndcs)
|
||||
free(dcs);
|
||||
}
|
||||
|
||||
static void
|
||||
dup_dest_constraint_hop(const struct dest_constraint_hop *dch,
|
||||
struct dest_constraint_hop *out)
|
||||
{
|
||||
u_int i;
|
||||
int r;
|
||||
|
||||
out->user = dch->user == NULL ? NULL : xstrdup(dch->user);
|
||||
out->hostname = dch->hostname == NULL ? NULL : xstrdup(dch->hostname);
|
||||
out->is_ca = dch->is_ca;
|
||||
out->nkeys = dch->nkeys;
|
||||
out->keys = out->nkeys == 0 ? NULL :
|
||||
xcalloc(out->nkeys, sizeof(*out->keys));
|
||||
out->key_is_ca = out->nkeys == 0 ? NULL :
|
||||
xcalloc(out->nkeys, sizeof(*out->key_is_ca));
|
||||
for (i = 0; i < dch->nkeys; i++) {
|
||||
if (dch->keys[i] != NULL &&
|
||||
(r = sshkey_from_private(dch->keys[i],
|
||||
&(out->keys[i]))) != 0)
|
||||
fatal_fr(r, "copy key");
|
||||
out->key_is_ca[i] = dch->key_is_ca[i];
|
||||
}
|
||||
}
|
||||
|
||||
static struct dest_constraint *
|
||||
dup_dest_constraints(const struct dest_constraint *dcs, size_t ndcs)
|
||||
{
|
||||
size_t i;
|
||||
struct dest_constraint *ret;
|
||||
|
||||
if (ndcs == 0)
|
||||
return NULL;
|
||||
ret = xcalloc(ndcs, sizeof(*ret));
|
||||
for (i = 0; i < ndcs; i++) {
|
||||
dup_dest_constraint_hop(&dcs[i].from, &ret[i].from);
|
||||
dup_dest_constraint_hop(&dcs[i].to, &ret[i].to);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CONSTRAINTS
|
||||
static void
|
||||
dump_dest_constraint_hop(const struct dest_constraint_hop *dch)
|
||||
{
|
||||
u_int i;
|
||||
char *fp;
|
||||
|
||||
debug_f("user %s hostname %s is_ca %d nkeys %u",
|
||||
dch->user == NULL ? "(null)" : dch->user,
|
||||
dch->hostname == NULL ? "(null)" : dch->hostname,
|
||||
dch->is_ca, dch->nkeys);
|
||||
for (i = 0; i < dch->nkeys; i++) {
|
||||
fp = NULL;
|
||||
if (dch->keys[i] != NULL &&
|
||||
(fp = sshkey_fingerprint(dch->keys[i],
|
||||
SSH_FP_HASH_DEFAULT, SSH_FP_DEFAULT)) == NULL)
|
||||
fatal_f("fingerprint failed");
|
||||
debug_f("key %u/%u: %s%s%s key_is_ca %d", i, dch->nkeys,
|
||||
dch->keys[i] == NULL ? "" : sshkey_ssh_name(dch->keys[i]),
|
||||
dch->keys[i] == NULL ? "" : " ",
|
||||
dch->keys[i] == NULL ? "none" : fp,
|
||||
dch->key_is_ca[i]);
|
||||
free(fp);
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG_CONSTRAINTS */
|
||||
|
||||
static void
|
||||
dump_dest_constraints(const char *context,
|
||||
const struct dest_constraint *dcs, size_t ndcs)
|
||||
{
|
||||
#ifdef DEBUG_CONSTRAINTS
|
||||
size_t i;
|
||||
|
||||
debug_f("%s: %zu constraints", context, ndcs);
|
||||
for (i = 0; i < ndcs; i++) {
|
||||
debug_f("constraint %zu / %zu: from: ", i, ndcs);
|
||||
dump_dest_constraint_hop(&dcs[i].from);
|
||||
debug_f("constraint %zu / %zu: to: ", i, ndcs);
|
||||
dump_dest_constraint_hop(&dcs[i].to);
|
||||
}
|
||||
debug_f("done for %s", context);
|
||||
#endif /* DEBUG_CONSTRAINTS */
|
||||
}
|
||||
|
||||
static void
|
||||
free_identity(Identity *id)
|
||||
{
|
||||
@ -377,6 +465,10 @@ identity_permitted(Identity *id, SocketEntry *e, char *user,
|
||||
e->nsession_ids, id->ndest_constraints);
|
||||
if (id->ndest_constraints == 0)
|
||||
return 0; /* unconstrained */
|
||||
if (e->session_bind_attempted && e->nsession_ids == 0) {
|
||||
error_f("previous session bind failed on socket");
|
||||
return -1;
|
||||
}
|
||||
if (e->nsession_ids == 0)
|
||||
return 0; /* local use */
|
||||
/*
|
||||
@ -456,6 +548,12 @@ identity_permitted(Identity *id, SocketEntry *e, char *user,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
socket_is_remote(SocketEntry *e)
|
||||
{
|
||||
return e->session_bind_attempted || (e->nsession_ids != 0);
|
||||
}
|
||||
|
||||
/* return matching private key for given public key */
|
||||
static Identity *
|
||||
lookup_identity(struct sshkey *key)
|
||||
@ -505,13 +603,22 @@ process_request_identities(SocketEntry *e)
|
||||
Identity *id;
|
||||
struct sshbuf *msg, *keys;
|
||||
int r;
|
||||
u_int nentries = 0;
|
||||
u_int i = 0, nentries = 0;
|
||||
char *fp;
|
||||
|
||||
debug2_f("entering");
|
||||
|
||||
if ((msg = sshbuf_new()) == NULL || (keys = sshbuf_new()) == NULL)
|
||||
fatal_f("sshbuf_new failed");
|
||||
TAILQ_FOREACH(id, &idtab->idlist, next) {
|
||||
if ((fp = sshkey_fingerprint(id->key, SSH_FP_HASH_DEFAULT,
|
||||
SSH_FP_DEFAULT)) == NULL)
|
||||
fatal_f("fingerprint failed");
|
||||
debug_f("key %u / %u: %s %s", i++, idtab->nentries,
|
||||
sshkey_ssh_name(id->key), fp);
|
||||
dump_dest_constraints(__func__,
|
||||
id->dest_constraints, id->ndest_constraints);
|
||||
free(fp);
|
||||
/* identity not visible, don't include in response */
|
||||
if (identity_permitted(id, e, NULL, NULL, NULL) != 0)
|
||||
continue;
|
||||
@ -1051,11 +1158,14 @@ parse_dest_constraint(struct sshbuf *m, struct dest_constraint *dc)
|
||||
|
||||
static int
|
||||
parse_key_constraint_extension(struct sshbuf *m, char **sk_providerp,
|
||||
struct dest_constraint **dcsp, size_t *ndcsp)
|
||||
struct dest_constraint **dcsp, size_t *ndcsp, int *cert_onlyp,
|
||||
struct sshkey ***certs, size_t *ncerts)
|
||||
{
|
||||
char *ext_name = NULL;
|
||||
int r;
|
||||
struct sshbuf *b = NULL;
|
||||
u_char v;
|
||||
struct sshkey *k;
|
||||
|
||||
if ((r = sshbuf_get_cstring(m, &ext_name, NULL)) != 0) {
|
||||
error_fr(r, "parse constraint extension");
|
||||
@ -1098,6 +1208,36 @@ parse_key_constraint_extension(struct sshbuf *m, char **sk_providerp,
|
||||
*dcsp + (*ndcsp)++)) != 0)
|
||||
goto out; /* error already logged */
|
||||
}
|
||||
} else if (strcmp(ext_name,
|
||||
"associated-certs-v00@openssh.com") == 0) {
|
||||
if (certs == NULL || ncerts == NULL || cert_onlyp == NULL) {
|
||||
error_f("%s not valid here", ext_name);
|
||||
r = SSH_ERR_INVALID_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
if (*certs != NULL) {
|
||||
error_f("%s already set", ext_name);
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshbuf_get_u8(m, &v)) != 0 ||
|
||||
(r = sshbuf_froms(m, &b)) != 0) {
|
||||
error_fr(r, "parse %s", ext_name);
|
||||
goto out;
|
||||
}
|
||||
*cert_onlyp = v != 0;
|
||||
while (sshbuf_len(b) != 0) {
|
||||
if (*ncerts >= AGENT_MAX_EXT_CERTS) {
|
||||
error_f("too many %s constraints", ext_name);
|
||||
goto out;
|
||||
}
|
||||
*certs = xrecallocarray(*certs, *ncerts, *ncerts + 1,
|
||||
sizeof(**certs));
|
||||
if ((r = sshkey_froms(b, &k)) != 0) {
|
||||
error_fr(r, "parse key");
|
||||
goto out;
|
||||
}
|
||||
(*certs)[(*ncerts)++] = k;
|
||||
}
|
||||
} else {
|
||||
error_f("unsupported constraint \"%s\"", ext_name);
|
||||
r = SSH_ERR_FEATURE_UNSUPPORTED;
|
||||
@ -1114,7 +1254,8 @@ parse_key_constraint_extension(struct sshbuf *m, char **sk_providerp,
|
||||
static int
|
||||
parse_key_constraints(struct sshbuf *m, struct sshkey *k, time_t *deathp,
|
||||
u_int *secondsp, int *confirmp, char **sk_providerp,
|
||||
struct dest_constraint **dcsp, size_t *ndcsp)
|
||||
struct dest_constraint **dcsp, size_t *ndcsp,
|
||||
int *cert_onlyp, size_t *ncerts, struct sshkey ***certs)
|
||||
{
|
||||
u_char ctype;
|
||||
int r;
|
||||
@ -1169,7 +1310,8 @@ parse_key_constraints(struct sshbuf *m, struct sshkey *k, time_t *deathp,
|
||||
break;
|
||||
case SSH_AGENT_CONSTRAIN_EXTENSION:
|
||||
if ((r = parse_key_constraint_extension(m,
|
||||
sk_providerp, dcsp, ndcsp)) != 0)
|
||||
sk_providerp, dcsp, ndcsp,
|
||||
cert_onlyp, certs, ncerts)) != 0)
|
||||
goto out; /* error already logged */
|
||||
break;
|
||||
default:
|
||||
@ -1206,11 +1348,13 @@ process_add_identity(SocketEntry *e)
|
||||
goto out;
|
||||
}
|
||||
if (parse_key_constraints(e->request, k, &death, &seconds, &confirm,
|
||||
&sk_provider, &dest_constraints, &ndest_constraints) != 0) {
|
||||
&sk_provider, &dest_constraints, &ndest_constraints,
|
||||
NULL, NULL, NULL) != 0) {
|
||||
error_f("failed to parse constraints");
|
||||
sshbuf_reset(e->request);
|
||||
goto out;
|
||||
}
|
||||
dump_dest_constraints(__func__, dest_constraints, ndest_constraints);
|
||||
|
||||
if (sk_provider != NULL) {
|
||||
if (!sshkey_is_sk(k)) {
|
||||
@ -1221,7 +1365,7 @@ process_add_identity(SocketEntry *e)
|
||||
if (strcasecmp(sk_provider, "internal") == 0) {
|
||||
debug_f("internal provider");
|
||||
} else {
|
||||
if (e->nsession_ids != 0 && !remote_add_provider) {
|
||||
if (socket_is_remote(e) && !remote_add_provider) {
|
||||
verbose("failed add of SK provider \"%.100s\": "
|
||||
"remote addition of providers is disabled",
|
||||
sk_provider);
|
||||
@ -1365,6 +1509,32 @@ no_identities(SocketEntry *e)
|
||||
sshbuf_free(msg);
|
||||
}
|
||||
|
||||
/* Add an identity to idlist; takes ownership of 'key' and 'comment' */
|
||||
static void
|
||||
add_p11_identity(struct sshkey *key, char *comment, const char *provider,
|
||||
time_t death, u_int confirm, struct dest_constraint *dest_constraints,
|
||||
size_t ndest_constraints)
|
||||
{
|
||||
Identity *id;
|
||||
|
||||
if (lookup_identity(key) != NULL) {
|
||||
sshkey_free(key);
|
||||
free(comment);
|
||||
return;
|
||||
}
|
||||
id = xcalloc(1, sizeof(Identity));
|
||||
id->key = key;
|
||||
id->comment = comment;
|
||||
id->provider = xstrdup(provider);
|
||||
id->death = death;
|
||||
id->confirm = confirm;
|
||||
id->dest_constraints = dup_dest_constraints(dest_constraints,
|
||||
ndest_constraints);
|
||||
id->ndest_constraints = ndest_constraints;
|
||||
TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
|
||||
idtab->nentries++;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PKCS11
|
||||
static void
|
||||
process_add_smartcard_key(SocketEntry *e)
|
||||
@ -1375,9 +1545,10 @@ process_add_smartcard_key(SocketEntry *e)
|
||||
u_int seconds = 0;
|
||||
time_t death = 0;
|
||||
struct sshkey **keys = NULL, *k;
|
||||
Identity *id;
|
||||
struct dest_constraint *dest_constraints = NULL;
|
||||
size_t ndest_constraints = 0;
|
||||
size_t j, ndest_constraints = 0, ncerts = 0;
|
||||
struct sshkey **certs = NULL;
|
||||
int cert_only = 0;
|
||||
|
||||
debug2_f("entering");
|
||||
if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
|
||||
@ -1386,11 +1557,13 @@ process_add_smartcard_key(SocketEntry *e)
|
||||
goto send;
|
||||
}
|
||||
if (parse_key_constraints(e->request, NULL, &death, &seconds, &confirm,
|
||||
NULL, &dest_constraints, &ndest_constraints) != 0) {
|
||||
NULL, &dest_constraints, &ndest_constraints, &cert_only,
|
||||
&ncerts, &certs) != 0) {
|
||||
error_f("failed to parse constraints");
|
||||
goto send;
|
||||
}
|
||||
if (e->nsession_ids != 0 && !remote_add_provider) {
|
||||
dump_dest_constraints(__func__, dest_constraints, ndest_constraints);
|
||||
if (socket_is_remote(e) && !remote_add_provider) {
|
||||
verbose("failed PKCS#11 add of \"%.100s\": remote addition of "
|
||||
"providers is disabled", provider);
|
||||
goto send;
|
||||
@ -1411,26 +1584,28 @@ process_add_smartcard_key(SocketEntry *e)
|
||||
|
||||
count = pkcs11_add_provider(canonical_provider, pin, &keys, &comments);
|
||||
for (i = 0; i < count; i++) {
|
||||
k = keys[i];
|
||||
if (lookup_identity(k) == NULL) {
|
||||
id = xcalloc(1, sizeof(Identity));
|
||||
id->key = k;
|
||||
keys[i] = NULL; /* transferred */
|
||||
id->provider = xstrdup(canonical_provider);
|
||||
if (*comments[i] != '\0') {
|
||||
id->comment = comments[i];
|
||||
comments[i] = NULL; /* transferred */
|
||||
} else {
|
||||
id->comment = xstrdup(canonical_provider);
|
||||
}
|
||||
id->death = death;
|
||||
id->confirm = confirm;
|
||||
id->dest_constraints = dest_constraints;
|
||||
id->ndest_constraints = ndest_constraints;
|
||||
dest_constraints = NULL; /* transferred */
|
||||
ndest_constraints = 0;
|
||||
TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
|
||||
idtab->nentries++;
|
||||
if (comments[i] == NULL || comments[i][0] == '\0') {
|
||||
free(comments[i]);
|
||||
comments[i] = xstrdup(canonical_provider);
|
||||
}
|
||||
for (j = 0; j < ncerts; j++) {
|
||||
if (!sshkey_is_cert(certs[j]))
|
||||
continue;
|
||||
if (!sshkey_equal_public(keys[i], certs[j]))
|
||||
continue;
|
||||
if (pkcs11_make_cert(keys[i], certs[j], &k) != 0)
|
||||
continue;
|
||||
add_p11_identity(k, xstrdup(comments[i]),
|
||||
canonical_provider, death, confirm,
|
||||
dest_constraints, ndest_constraints);
|
||||
success = 1;
|
||||
}
|
||||
if (!cert_only && lookup_identity(keys[i]) == NULL) {
|
||||
add_p11_identity(keys[i], comments[i],
|
||||
canonical_provider, death, confirm,
|
||||
dest_constraints, ndest_constraints);
|
||||
keys[i] = NULL; /* transferred */
|
||||
comments[i] = NULL; /* transferred */
|
||||
success = 1;
|
||||
}
|
||||
/* XXX update constraints for existing keys */
|
||||
@ -1443,6 +1618,9 @@ send:
|
||||
free(keys);
|
||||
free(comments);
|
||||
free_dest_constraints(dest_constraints, ndest_constraints);
|
||||
for (j = 0; j < ncerts; j++)
|
||||
sshkey_free(certs[j]);
|
||||
free(certs);
|
||||
send_status(e, success);
|
||||
}
|
||||
|
||||
@ -1500,6 +1678,7 @@ process_ext_session_bind(SocketEntry *e)
|
||||
u_char fwd = 0;
|
||||
|
||||
debug2_f("entering");
|
||||
e->session_bind_attempted = 1;
|
||||
if ((r = sshkey_froms(e->request, &key)) != 0 ||
|
||||
(r = sshbuf_froms(e->request, &sid)) != 0 ||
|
||||
(r = sshbuf_froms(e->request, &sig)) != 0 ||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh-pkcs11-client.c,v 1.18 2023/07/19 14:03:45 djm Exp $ */
|
||||
/* $OpenBSD: ssh-pkcs11-client.c,v 1.19 2023/12/18 14:46:56 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2010 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2014 Pedro Martelletto. All rights reserved.
|
||||
@ -405,6 +405,60 @@ wrap_key(struct helper *helper, struct sshkey *k)
|
||||
helper->path, helper->nrsa, helper->nec);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a private PKCS#11-backed certificate by grafting a previously-loaded
|
||||
* PKCS#11 private key and a public certificate key.
|
||||
*/
|
||||
int
|
||||
pkcs11_make_cert(const struct sshkey *priv,
|
||||
const struct sshkey *certpub, struct sshkey **certprivp)
|
||||
{
|
||||
struct helper *helper = NULL;
|
||||
struct sshkey *ret;
|
||||
int r;
|
||||
|
||||
debug3_f("private key type %s cert type %s", sshkey_type(priv),
|
||||
sshkey_type(certpub));
|
||||
*certprivp = NULL;
|
||||
if (!sshkey_is_cert(certpub) || sshkey_is_cert(priv) ||
|
||||
!sshkey_equal_public(priv, certpub)) {
|
||||
error_f("private key %s doesn't match cert %s",
|
||||
sshkey_type(priv), sshkey_type(certpub));
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
*certprivp = NULL;
|
||||
if (priv->type == KEY_RSA) {
|
||||
if ((helper = helper_by_rsa(priv->rsa)) == NULL ||
|
||||
helper->fd == -1)
|
||||
fatal_f("no helper for PKCS11 RSA key");
|
||||
if ((r = sshkey_from_private(priv, &ret)) != 0)
|
||||
fatal_fr(r, "copy key");
|
||||
RSA_set_method(ret->rsa, helper->rsa_meth);
|
||||
if (helper->nrsa++ >= INT_MAX)
|
||||
fatal_f("RSA refcount error");
|
||||
} else if (priv->type == KEY_ECDSA) {
|
||||
if ((helper = helper_by_ec(priv->ecdsa)) == NULL ||
|
||||
helper->fd == -1)
|
||||
fatal_f("no helper for PKCS11 EC key");
|
||||
if ((r = sshkey_from_private(priv, &ret)) != 0)
|
||||
fatal_fr(r, "copy key");
|
||||
EC_KEY_set_method(ret->ecdsa, helper->ec_meth);
|
||||
if (helper->nec++ >= INT_MAX)
|
||||
fatal_f("EC refcount error");
|
||||
} else
|
||||
fatal_f("unknown key type %s", sshkey_type(priv));
|
||||
|
||||
ret->flags |= SSHKEY_FLAG_EXT;
|
||||
if ((r = sshkey_to_certified(ret)) != 0 ||
|
||||
(r = sshkey_cert_copy(certpub, ret)) != 0)
|
||||
fatal_fr(r, "graft certificate");
|
||||
debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
|
||||
helper->path, helper->nrsa, helper->nec);
|
||||
/* success */
|
||||
*certprivp = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pkcs11_start_helper_methods(struct helper *helper)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh-pkcs11.h,v 1.6 2020/01/25 00:03:36 djm Exp $ */
|
||||
/* $OpenBSD: ssh-pkcs11.h,v 1.7 2023/12/18 14:46:56 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2010 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -35,6 +35,9 @@ struct sshkey *
|
||||
u_int32_t *);
|
||||
#endif
|
||||
|
||||
/* Only available in ssh-pkcs11-client.c so far */
|
||||
int pkcs11_make_cert(const struct sshkey *,
|
||||
const struct sshkey *, struct sshkey **);
|
||||
#if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11)
|
||||
#undef ENABLE_PKCS11
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh.c,v 1.598 2023/10/12 02:48:43 djm Exp $ */
|
||||
/* $OpenBSD: ssh.c,v 1.599 2023/12/18 14:47:44 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -610,6 +610,41 @@ ssh_conn_info_free(struct ssh_conn_info *cinfo)
|
||||
free(cinfo);
|
||||
}
|
||||
|
||||
static int
|
||||
valid_hostname(const char *s)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (*s == '-')
|
||||
return 0;
|
||||
for (i = 0; s[i] != 0; i++) {
|
||||
if (strchr("'`\"$\\;&<>|(){}", s[i]) != NULL ||
|
||||
isspace((u_char)s[i]) || iscntrl((u_char)s[i]))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
valid_ruser(const char *s)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (*s == '-')
|
||||
return 0;
|
||||
for (i = 0; s[i] != 0; i++) {
|
||||
if (strchr("'`\";&<>|(){}", s[i]) != NULL)
|
||||
return 0;
|
||||
/* Disallow '-' after whitespace */
|
||||
if (isspace((u_char)s[i]) && s[i + 1] == '-')
|
||||
return 0;
|
||||
/* Disallow \ in last position */
|
||||
if (s[i] == '\\' && s[i + 1] == '\0')
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main program for the ssh client.
|
||||
*/
|
||||
@ -1092,6 +1127,10 @@ main(int ac, char **av)
|
||||
if (!host)
|
||||
usage();
|
||||
|
||||
if (!valid_hostname(host))
|
||||
fatal("hostname contains invalid characters");
|
||||
if (options.user != NULL && !valid_ruser(options.user))
|
||||
fatal("remote username contains invalid characters");
|
||||
options.host_arg = xstrdup(host);
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: sshconnect2.c,v 1.369 2023/12/13 03:28:19 djm Exp $ */
|
||||
/* $OpenBSD: sshconnect2.c,v 1.371 2023/12/18 14:45:49 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2008 Damien Miller. All rights reserved.
|
||||
@ -351,7 +351,6 @@ struct cauthmethod {
|
||||
};
|
||||
|
||||
static int input_userauth_service_accept(int, u_int32_t, struct ssh *);
|
||||
static int input_userauth_ext_info(int, u_int32_t, struct ssh *);
|
||||
static int input_userauth_success(int, u_int32_t, struct ssh *);
|
||||
static int input_userauth_failure(int, u_int32_t, struct ssh *);
|
||||
static int input_userauth_banner(int, u_int32_t, struct ssh *);
|
||||
@ -453,10 +452,8 @@ ssh_userauth2(struct ssh *ssh, const char *local_user,
|
||||
authctxt.mech_tried = 0;
|
||||
#endif
|
||||
authctxt.agent_fd = -1;
|
||||
pubkey_prepare(ssh, &authctxt);
|
||||
if (authctxt.method == NULL) {
|
||||
if (authctxt.method == NULL)
|
||||
fatal_f("internal error: cannot send userauth none request");
|
||||
}
|
||||
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_REQUEST)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, "ssh-userauth")) != 0 ||
|
||||
@ -465,7 +462,7 @@ ssh_userauth2(struct ssh *ssh, const char *local_user,
|
||||
|
||||
ssh->authctxt = &authctxt;
|
||||
ssh_dispatch_init(ssh, &input_userauth_error);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, kex_input_ext_info);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept);
|
||||
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt.success); /* loop until success */
|
||||
pubkey_cleanup(ssh);
|
||||
@ -515,7 +512,9 @@ input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh)
|
||||
/* initial userauth request */
|
||||
userauth_none(ssh);
|
||||
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_error);
|
||||
/* accept EXT_INFO at any time during userauth */
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, ssh->kex->ext_info_s ?
|
||||
&kex_input_ext_info : &input_userauth_error);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
|
||||
@ -524,12 +523,6 @@ input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
input_userauth_ext_info(int type, u_int32_t seqnr, struct ssh *ssh)
|
||||
{
|
||||
return kex_input_ext_info(type, seqnr, ssh);
|
||||
}
|
||||
|
||||
void
|
||||
userauth(struct ssh *ssh, char *authlist)
|
||||
{
|
||||
@ -608,6 +601,7 @@ input_userauth_success(int type, u_int32_t seq, struct ssh *ssh)
|
||||
free(authctxt->methoddata);
|
||||
authctxt->methoddata = NULL;
|
||||
authctxt->success = 1; /* break out */
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, dispatch_protocol_error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1677,10 +1671,10 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt)
|
||||
struct identity *id, *id2, *tmp;
|
||||
struct idlist agent, files, *preferred;
|
||||
struct sshkey *key;
|
||||
int agent_fd = -1, i, r, found;
|
||||
int disallowed, agent_fd = -1, i, r, found;
|
||||
size_t j;
|
||||
struct ssh_identitylist *idlist;
|
||||
char *ident;
|
||||
char *cp, *ident;
|
||||
|
||||
TAILQ_INIT(&agent); /* keys from the agent */
|
||||
TAILQ_INIT(&files); /* keys from the config file */
|
||||
@ -1798,16 +1792,30 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt)
|
||||
TAILQ_CONCAT(preferred, &files, next);
|
||||
/* finally, filter by PubkeyAcceptedAlgorithms */
|
||||
TAILQ_FOREACH_SAFE(id, preferred, next, id2) {
|
||||
if (id->key != NULL && !key_type_allowed_by_config(id->key)) {
|
||||
debug("Skipping %s key %s - "
|
||||
"corresponding algo not in PubkeyAcceptedAlgorithms",
|
||||
sshkey_ssh_name(id->key), id->filename);
|
||||
TAILQ_REMOVE(preferred, id, next);
|
||||
sshkey_free(id->key);
|
||||
free(id->filename);
|
||||
memset(id, 0, sizeof(*id));
|
||||
disallowed = 0;
|
||||
cp = NULL;
|
||||
if (id->key == NULL)
|
||||
continue;
|
||||
if (!key_type_allowed_by_config(id->key)) {
|
||||
debug("Skipping %s key %s - corresponding algorithm "
|
||||
"not in PubkeyAcceptedAlgorithms",
|
||||
sshkey_ssh_name(id->key), id->filename);
|
||||
disallowed = 1;
|
||||
} else if (ssh->kex->server_sig_algs != NULL &&
|
||||
(cp = key_sig_algorithm(ssh, id->key)) == NULL) {
|
||||
debug("Skipping %s key %s - corresponding algorithm "
|
||||
"not supported by server",
|
||||
sshkey_ssh_name(id->key), id->filename);
|
||||
disallowed = 1;
|
||||
}
|
||||
free(cp);
|
||||
if (!disallowed)
|
||||
continue;
|
||||
/* remove key */
|
||||
TAILQ_REMOVE(preferred, id, next);
|
||||
sshkey_free(id->key);
|
||||
free(id->filename);
|
||||
memset(id, 0, sizeof(*id));
|
||||
}
|
||||
/* List the keys we plan on using */
|
||||
TAILQ_FOREACH_SAFE(id, preferred, next, id2) {
|
||||
@ -1853,6 +1861,12 @@ userauth_pubkey(struct ssh *ssh)
|
||||
Identity *id;
|
||||
int sent = 0;
|
||||
char *ident;
|
||||
static int prepared;
|
||||
|
||||
if (!prepared) {
|
||||
pubkey_prepare(ssh, authctxt);
|
||||
prepared = 1;
|
||||
}
|
||||
|
||||
while ((id = TAILQ_FIRST(&authctxt->keys))) {
|
||||
if (id->tried++)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: sshd.c,v 1.600 2023/03/08 04:43:12 guenther Exp $ */
|
||||
/* $OpenBSD: sshd.c,v 1.601 2023/12/18 14:45:49 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -2240,7 +2240,9 @@ do_ssh2_kex(struct ssh *ssh)
|
||||
/* start key exchange */
|
||||
if ((r = kex_setup(ssh, myproposal)) != 0)
|
||||
fatal_r(r, "kex_setup");
|
||||
kex_set_server_sig_algs(ssh, options.pubkey_accepted_algos);
|
||||
kex = ssh->kex;
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server;
|
||||
kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server;
|
||||
|
@ -1,3 +1,3 @@
|
||||
/* $OpenBSD: version.h,v 1.99 2023/10/04 04:04:09 djm Exp $ */
|
||||
/* $OpenBSD: version.h,v 1.100 2023/12/18 14:48:44 djm Exp $ */
|
||||
|
||||
#define SSH_VERSION "OpenSSH_9.5"
|
||||
#define SSH_VERSION "OpenSSH_9.6"
|
||||
|
@ -1,3 +1,3 @@
|
||||
/* $OpenBSD: version.h,v 1.18 2023/10/02 13:31:32 claudio Exp $ */
|
||||
/* $OpenBSD: version.h,v 1.19 2023/12/18 09:51:06 benno Exp $ */
|
||||
|
||||
#define RPKI_VERSION "8.6"
|
||||
#define RPKI_VERSION "8.7"
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: application_internal.c,v 1.9 2023/12/12 20:15:49 martijn Exp $ */
|
||||
/* $OpenBSD: application_internal.c,v 1.10 2023/12/18 09:42:57 martijn Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Martijn van Duren <martijn@openbsd.org>
|
||||
@ -130,8 +130,6 @@ appl_internal_init(void)
|
||||
NULL);
|
||||
appl_internal_object(&OID(MIB_snmpInReadOnlys), appl_internal_snmp,
|
||||
NULL);
|
||||
appl_internal_object(&OID(MIB_snmpInReadOnlys), appl_internal_snmp,
|
||||
NULL);
|
||||
appl_internal_object(&OID(MIB_snmpInGenErrs), appl_internal_snmp, NULL);
|
||||
appl_internal_object(&OID(MIB_snmpInTotalReqVars), appl_internal_snmp,
|
||||
NULL);
|
||||
@ -253,6 +251,7 @@ appl_internal_object(struct ber_oid *oid,
|
||||
struct ber_element *(*getnext)(int8_t, struct ber_oid *))
|
||||
{
|
||||
struct appl_internal_object *obj;
|
||||
char buf[1024];
|
||||
|
||||
if ((obj = calloc(1, sizeof(*obj))) == NULL)
|
||||
fatal(NULL);
|
||||
@ -261,7 +260,10 @@ appl_internal_object(struct ber_oid *oid,
|
||||
obj->getnext = getnext;
|
||||
obj->stringval = NULL;
|
||||
|
||||
RB_INSERT(appl_internal_objects, &appl_internal_objects, obj);
|
||||
if (RB_INSERT(appl_internal_objects,
|
||||
&appl_internal_objects, obj) != NULL)
|
||||
fatalx("%s: %s already registered", __func__,
|
||||
smi_oid2string(oid, buf, sizeof(buf), 0));
|
||||
}
|
||||
|
||||
const char *
|
||||
@ -351,6 +353,8 @@ appl_internal_get(struct appl_backend *backend, __unused int32_t transactionid,
|
||||
resp[i - 1].av_next = NULL;
|
||||
|
||||
appl_response(backend, requestid, APPL_ERROR_NOERROR, 0, resp);
|
||||
|
||||
free(resp);
|
||||
return;
|
||||
|
||||
fail:
|
||||
@ -434,6 +438,8 @@ appl_internal_getnext(struct appl_backend *backend,
|
||||
resp[i - 1].av_next = NULL;
|
||||
|
||||
appl_response(backend, requestid, APPL_ERROR_NOERROR, 0, resp);
|
||||
|
||||
free(resp);
|
||||
return;
|
||||
|
||||
fail:
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: parse.y,v 1.83 2023/11/21 08:47:04 martijn Exp $ */
|
||||
/* $OpenBSD: parse.y,v 1.85 2023/12/18 16:58:26 martijn Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
|
||||
@ -105,7 +105,7 @@ static uint8_t engineid[SNMPD_MAXENGINEIDLEN];
|
||||
static int32_t enginepen;
|
||||
static size_t engineidlen;
|
||||
|
||||
int host(const char *, const char *, int,
|
||||
int host(const char *, const char *, int, int,
|
||||
struct sockaddr_storage *, int);
|
||||
int listen_add(struct sockaddr_storage *, int, int);
|
||||
|
||||
@ -395,8 +395,8 @@ listen_udptcp : listenproto STRING port listenflags {
|
||||
}
|
||||
|
||||
for (i = 0; i < addresslen; i++) {
|
||||
nhosts = host(address[i], port, $1, ss, nitems(ss));
|
||||
if (nhosts < 1) {
|
||||
if ((nhosts = host(address[i], port, AF_UNSPEC,
|
||||
$1, ss, nitems(ss))) < 1) {
|
||||
yyerror("invalid address: %s", $2);
|
||||
free($2);
|
||||
free($3);
|
||||
@ -1021,7 +1021,8 @@ hostdef : STRING hostoid hostauth srcaddr {
|
||||
YYERROR;
|
||||
}
|
||||
|
||||
if (host($1, SNMPTRAP_PORT, SOCK_DGRAM, &ss, 1) <= 0) {
|
||||
if (host($1, SNMPTRAP_PORT, AF_UNSPEC, SOCK_DGRAM,
|
||||
&ss, 1) <= 0) {
|
||||
yyerror("invalid host: %s", $1);
|
||||
free($1);
|
||||
free($2);
|
||||
@ -1033,8 +1034,10 @@ hostdef : STRING hostoid hostauth srcaddr {
|
||||
free($1);
|
||||
memcpy(&(tr->ta_ss), &ss, sizeof(ss));
|
||||
if ($4 != NULL) {
|
||||
if (host($1, "0", SOCK_DGRAM, &ss, 1) <= 0) {
|
||||
yyerror("invalid host: %s", $1);
|
||||
if (host($4, "0", ss.ss_family, SOCK_DGRAM,
|
||||
&ss, 1) <= 0) {
|
||||
yyerror("invalid source-address: %s",
|
||||
$4);
|
||||
free($2);
|
||||
free($3.data);
|
||||
free($4);
|
||||
@ -1702,11 +1705,12 @@ parse_config(const char *filename, u_int flags)
|
||||
|
||||
/* Setup default listen addresses */
|
||||
if (TAILQ_EMPTY(&conf->sc_addresses)) {
|
||||
if (host("0.0.0.0", SNMP_PORT, SOCK_DGRAM, &ss, 1) != 1)
|
||||
if (host("0.0.0.0", SNMP_PORT, AF_INET, SOCK_DGRAM,
|
||||
&ss, 1) != 1)
|
||||
fatal("Unexpected resolving of 0.0.0.0");
|
||||
if (listen_add(&ss, SOCK_DGRAM, 0) == -1)
|
||||
fatal("calloc");
|
||||
if (host("::", SNMP_PORT, SOCK_DGRAM, &ss, 1) != 1)
|
||||
if (host("::", SNMP_PORT, AF_INET6, SOCK_DGRAM, &ss, 1) != 1)
|
||||
fatal("Unexpected resolving of ::");
|
||||
if (listen_add(&ss, SOCK_DGRAM, 0) == -1)
|
||||
fatal("calloc");
|
||||
@ -1843,14 +1847,14 @@ symget(const char *nam)
|
||||
}
|
||||
|
||||
int
|
||||
host(const char *s, const char *port, int type, struct sockaddr_storage *ss,
|
||||
int max)
|
||||
host(const char *s, const char *port, int family, int type,
|
||||
struct sockaddr_storage *ss, int max)
|
||||
{
|
||||
struct addrinfo hints, *res0, *res;
|
||||
int error, i;
|
||||
|
||||
bzero(&hints, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = type;
|
||||
/*
|
||||
* Without AI_NUMERICHOST getaddrinfo might not resolve ip addresses
|
||||
|
Loading…
Reference in New Issue
Block a user