sync with OpenBSD -current

This commit is contained in:
purplerain 2023-12-18 23:55:01 +00:00
parent da785accdf
commit 659ea2942e
Signed by: purplerain
GPG Key ID: F42C07F07E2E35B7
39 changed files with 1318 additions and 384 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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,

View File

@ -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)

View File

@ -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) ";"

View File

@ -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

View 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

View 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"

View File

@ -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;

View File

@ -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);
}

View File

@ -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:

View File

@ -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);

View File

@ -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);

View File

@ -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 {

View File

@ -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

View File

@ -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 $

View File

@ -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 $

View File

@ -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");

View File

@ -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;

View File

@ -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,

View File

@ -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)

View File

@ -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;

View File

@ -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 */

View File

@ -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 *);

View File

@ -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);

View File

@ -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 ||

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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 ||

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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++)

View File

@ -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;

View File

@ -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"

View File

@ -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"

View File

@ -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:

View File

@ -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