Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tinyssh-tests/fail.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#define fail(x) fail_(__FILE__, __LINE__, (x))


static void fail_printdata(char *text, unsigned char *data, long long len) {
static void fail_printdata(const char *text, const unsigned char *data, long long len) {

long long i;

Expand Down
124 changes: 124 additions & 0 deletions tinyssh-tests/sshcrypto_key_sk_ed25519test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
20440414
Jó Ágila Bitsch
Public domain.
*/

#include <unistd.h>
#include <string.h>
#include "fail.h"
#include "sshcrypto.h"

static unsigned char authorized_keys[129] = "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAINNQKmYkYiy++sy5lWeN+N0SJsaDWPx9JYqlRgiZKbVlAAAABHNzaDo=\n";
static unsigned char id_sk_ed25519_bin[78] = {
0x00, 0x00, 0x00, 0x4a, // -> uint32 length (of the public key bytes to follow)
0x00, 0x00, 0x00, 0x1a, //-> uint32 length (of the public key type string)
0x73, 0x6b, 0x2d, 0x73, 0x73, 0x68, 0x2d, 0x65,
0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x40, 0x6f,
0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63,
0x6f, 0x6d, // -> string "sk-ssh-ed25519@openssh.com"
0x00, 0x00, 0x00, 0x20, // -> uint32 length (of the public key bytes)
0xd3, 0x50, 0x2a, 0x66, 0x24, 0x62, 0x2c, 0xbe,
0xfa, 0xcc, 0xb9, 0x95, 0x67, 0x8d, 0xf8, 0xdd,
0x12, 0x26, 0xc6, 0x83, 0x58, 0xfc, 0x7d, 0x25,
0x8a, 0xa5, 0x46, 0x08, 0x99, 0x29, 0xb5, 0x65, // -> 32 bytes of a ed25519 public key
0x00, 0x00, 0x00, 0x04, // -> uint32 length of application string
0x73, 0x73, 0x68, 0x3a, // -> application string "ssh:"

};
static unsigned char signature[107] = {
0x00, 0x00, 0x00, 0x67, // -> uint32 length (of the signature bytes to follow)
0x00, 0x00, 0x00, 0x1a, // -> uint32 length (of the signature algorithm name)
0x73, 0x6b, 0x2d, 0x73, 0x73, 0x68, 0x2d, 0x65,
0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x40, 0x6f,
0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63,
0x6f, 0x6d, // -> string "sk-ssh-ed25519@openssh.com"
0x00, 0x00, 0x00, 0x40, // -> uint32 length(=64) of signature itself
0x9c, 0xd3, 0xa1, 0xd9, 0xdc, 0x01, 0xcb, 0xdd,
0x0e, 0xe7, 0xbd, 0x29, 0x58, 0xcb, 0x79, 0x4a,
0x75, 0xd8, 0xb4, 0xef, 0x3b, 0x57, 0x24, 0xbe,
0x20, 0x39, 0x46, 0x0a, 0xdf, 0xcf, 0x15, 0x34,
0x38, 0xff, 0xe7, 0xcf, 0x0e, 0xa3, 0x1b, 0x2b,
0x75, 0xfd, 0x18, 0xd4, 0xab, 0x2a, 0x74, 0xc0,
0xab, 0x7f, 0x39, 0xc0, 0x0f, 0x66, 0x5d, 0x60,
0x11, 0x4d, 0xbb, 0xd8, 0xb8, 0xda, 0x4c, 0x05, // -> bytes of the signature
0x01, // -> (byte) flags -> user present
0x00, 0x00, 0x00, 0x08, // -> uint32 counter
};
static unsigned char message[96] = { // SSHSIG over the authorized_keys
0x53, 0x53, 0x48, 0x53, 0x49, 0x47, 0x00, 0x00,
0x00, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x73, 0x68,
0x61, 0x35, 0x31, 0x32, 0x00, 0x00, 0x00, 0x40,
0xa8, 0x0b, 0xb9, 0xab, 0x9d, 0xbc, 0x68, 0xa3,
0xef, 0x64, 0x18, 0x53, 0x22, 0xee, 0x31, 0xb0,
0x39, 0x26, 0x03, 0x39, 0x25, 0x29, 0x4e, 0xa9,
0x1b, 0xba, 0x3b, 0x6f, 0xf4, 0xb2, 0x7a, 0x90,
0xb5, 0xf5, 0xce, 0x5f, 0x4b, 0x15, 0xb5, 0xab,
0x98, 0xf5, 0xb9, 0x4c, 0xa3, 0x2f, 0x59, 0xbd,
0xa0, 0x1d, 0xc0, 0x42, 0x6d, 0xd6, 0x32, 0x35,
0xf0, 0x94, 0x0a, 0x5f, 0xe0, 0xe9, 0x83, 0xdf,
};

static void test_signopen(void) {
unsigned char pk[crypto_sign_ed25519_PUBLICKEYBYTES + 16];
unsigned char sig[69];
unsigned char buf_array[1024];
struct buf buf;
// unsigned long long len;
unsigned char om[1024];
unsigned long long omlen;

buf_init(&buf, buf_array, sizeof buf_array);

sk_ed25519_parsesignpk(pk, id_sk_ed25519_bin + 4, sizeof id_sk_ed25519_bin - 4);
sk_ed25519_putsignpk(&buf, pk);
if (memcmp(buf.buf, id_sk_ed25519_bin, sizeof id_sk_ed25519_bin)){
fail_printdata("id", id_sk_ed25519_bin, sizeof id_sk_ed25519_bin);
fail_printdata("buf", buf.buf, buf.len);
fail("sk_ed25519_putsignpk() failure, please report it !!!!!!!!!");
}
buf_purge(&buf);

sk_ed25519_putsignpkbase64(&buf,pk);
if (memcmp(buf.buf, authorized_keys + 27, sizeof authorized_keys - 29)){
fail_printdata("ak", authorized_keys, sizeof authorized_keys);
fail_printdata("buf", buf.buf, buf.len);
fail("sk_ed25519_putsignpkbase64() failure, please report it !!!!!!!!!");
}
buf_purge(&buf);


sk_ed25519_parsesignature(sig, signature + 4, sizeof signature - 4);
sk_ed25519_putsignature(&buf, sig);
if (memcmp(buf.buf, signature, sizeof signature)){
fail_printdata("insig", signature, sizeof signature);
fail_printdata("sig", sig, 69);
fail_printdata("buf", buf.buf, buf.len);
fail("sk_ed25519_putsignature() failure, please report it !!!!!!!!!");
}
buf_purge(&buf);


buf_put(&buf, sig, sizeof sig);
buf_put(&buf, message, sizeof message);

if (sk_ed25519_open(om, &omlen, buf.buf, buf.len, pk) != 0) {
fail_printdata("sm", buf.buf, buf.len);
fail_printdata("pk", pk, crypto_sign_ed25519_PUBLICKEYBYTES);
fail("sk_ed25519_open() failure, please report it !!!!!!!!!");
}

if (memcmp(buf.buf + 69, om, omlen)) {
fail_printdata("m", buf.buf, omlen);
fail_printdata("om", om, omlen);
fail("sk_ed25519_open() failure, messages do not match");
}
}


int main(void) {

test_signopen();
_exit(0);
}
5 changes: 4 additions & 1 deletion tinyssh-tests/subprocess_signtest.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ int main(void) {
if (mkdir(keydir, 0755) == -1) fail("unable to create test directory");
if (chdir(keydir) == -1) fail("unable to chdir to directory");
for (i = 0; sshcrypto_keys[i].name; ++i) {


if (sshcrypto_keys[i].sign_flagserver) continue;
if (sshcrypto_keys[i].sign_keypair(sshcrypto_keys[i].sign_publickey, sk) != 0) fail("unable to generate key pair");
umask(022);
create(sshcrypto_keys[i].sign_publickeyfilename, sshcrypto_keys[i].sign_publickey, sshcrypto_keys[i].sign_publickeybytes);
Expand All @@ -54,6 +55,8 @@ int main(void) {

for (i = 0; sshcrypto_keys[i].name; ++i) {

if (sshcrypto_keys[i].sign_flagserver) continue;

/* set globals */
sshcrypto_key_name = sshcrypto_keys[i].name;
sshcrypto_sign = sshcrypto_keys[i].sign;
Expand Down
1 change: 1 addition & 0 deletions tinyssh/LIBS
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ sshcrypto_kex_curve25519.o
sshcrypto_kex_sntrup761x25519.o
sshcrypto_key.o
sshcrypto_key_ed25519.o
sshcrypto_key_sk_ed25519.o
str.o
stringparser.o
subprocess_auth.o
Expand Down
1 change: 1 addition & 0 deletions tinyssh/SOURCES
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ sshcrypto_kex_curve25519
sshcrypto_kex_sntrup761x25519
sshcrypto_key
sshcrypto_key_ed25519
sshcrypto_key_sk_ed25519
str
stringparser
subprocess_auth
Expand Down
1 change: 1 addition & 0 deletions tinyssh/main_tinysshd_makekey.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ int main_tinysshd_makekey(int argc, char **argv) {
if (chdir(x) == -1) die_fatal("unable to chdir to directory", x, 0);

for (i = 0; sshcrypto_keys[i].name; ++i) {
if (sshcrypto_keys[i].sign_flagserver) continue;
if (sshcrypto_keys[i].sign_keypair(pk, sk) != 0) die_fatal("unable to generate key pair", x, 0);
umask(022);
create(x, sshcrypto_keys[i].sign_publickeyfilename, pk, sshcrypto_keys[i].sign_publickeybytes);
Expand Down
21 changes: 17 additions & 4 deletions tinyssh/sshcrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,16 @@ extern void sntrup761x25519_putkemkey(struct buf *, const unsigned char *);
#endif

/* key - sign */
#define sshcrypto_sign_PUBLICKEYMAX 32 /* space for ed25519 pk */
#define sshcrypto_sign_APPLICATIONMAX 32 /* space for sk application id */
#define sshcrypto_sign_PUBLICKEYMAX (32+sshcrypto_sign_APPLICATIONMAX) /* space for ed25519 pk */
#define sshcrypto_sign_SECRETKEYMAX 64 /* space for ed25519 sk */
#define sshcrypto_sign_MAX 64 /* space for ed25519 sig */
#define sshcrypto_sign_BASE64PUBLICKEYMAX 69 /* space for ed25519 in base64 + 0-terminator */
//#define sshcrypto_sign_MAX 64 /* space for ed25519 sig */
#define sshcrypto_sign_MAX (64+1+4) /* space for ed25519 sig + 1 byte flags + 4 byte counter*/
#define sshcrypto_sign_BASE64PUBLICKEYMAX 118 /* space for sk-ed25519 with 32 byte application id in base64 + 0-terminator */
#define sshcrypto_sign_BASE64PUBLICKEYMIN 69 /* space for ed25519 in base64 + 0-terminator */
#define sshcrypto_sign_NAMEMAX 12 /* space for string ssh-ed25519 + 0-terminator */
//#define sshcrypto_sign_NAMEMAX 12 /* space for string ssh-ed25519 + 0-terminator */
#define sshcrypto_sign_NAMEMAX 27 /* space for string sk-ssh-ed25519@openssh.com + 0-terminator */


struct sshcrypto_key {
const char *name;
Expand Down Expand Up @@ -114,6 +118,15 @@ extern void ed25519_putsignpkbase64(struct buf *, const unsigned char *);
extern int ed25519_parsesignpk(unsigned char *, const unsigned char *, long long);
extern int ed25519_parsesignature(unsigned char *, const unsigned char *, long long);
#endif
#ifdef crypto_sign_ed25519_BYTES
/* sshcrypto_key_sk_ed25519.c */
extern int sk_ed25519_open(unsigned char *, unsigned long long *, const unsigned char *, unsigned long long, const unsigned char *);
extern void sk_ed25519_putsignature(struct buf *, const unsigned char *);
extern void sk_ed25519_putsignpk(struct buf *, const unsigned char *);
extern void sk_ed25519_putsignpkbase64(struct buf *, const unsigned char *);
extern int sk_ed25519_parsesignpk(unsigned char *, const unsigned char *, long long);
extern int sk_ed25519_parsesignature(unsigned char *, const unsigned char *, long long);
#endif


/* cipher + mac */
Expand Down
21 changes: 21 additions & 0 deletions tinyssh/sshcrypto_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,27 @@ struct sshcrypto_key sshcrypto_keys[] = {
ed25519_parsesignpk,
},
#endif
#ifdef crypto_sign_ed25519_BYTES
{ "sk-ssh-ed25519@openssh.com",
0,
sk_ed25519_open,
0,
{0},
crypto_sign_ed25519_PUBLICKEYBYTES,
0,
crypto_sign_ed25519_BYTES + 5,
"",
"",
sshcrypto_TYPENEWCRYPTO,
1,
0,
sk_ed25519_putsignature,
sk_ed25519_putsignpk,
sk_ed25519_putsignpkbase64,
sk_ed25519_parsesignature,
sk_ed25519_parsesignpk,
},
#endif
#if 0
{ "pqkeyTODO",
crypto_sign_ed25519,
Expand Down
124 changes: 124 additions & 0 deletions tinyssh/sshcrypto_key_sk_ed25519.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
20240414
Jó Ágila Bitsch
Public domain.

Specification: https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.u2f?annotate=HEAD
*/

#include "crypto.h"
#include "packetparser.h"
#include "buf.h"
#include "byte.h"
#include "str.h"
#include "purge.h"
#include "sshcrypto.h"

#ifdef crypto_sign_ed25519_BYTES
int sk_ed25519_open(unsigned char *m, unsigned long long *mlen, const unsigned char *sm, unsigned long long n, const unsigned char *pk) {

unsigned char buf[crypto_sign_ed25519_BYTES + crypto_hash_sha256_BYTES + 1 + 4 + crypto_hash_sha256_BYTES];
unsigned long long buflen = sizeof(buf);
long long i;
int ret = 1;

byte_copy(buf, crypto_sign_ed25519_BYTES, sm);

// application
crypto_hash_sha256(buf + crypto_sign_ed25519_BYTES, pk+crypto_sign_ed25519_PUBLICKEYBYTES, str_len(pk+crypto_sign_ed25519_PUBLICKEYBYTES));

// flags + counter
byte_copy(buf + crypto_sign_ed25519_BYTES + crypto_hash_sha256_BYTES, 1 + 4, sm + crypto_sign_ed25519_BYTES);

// message
crypto_hash_sha256(buf + crypto_sign_ed25519_BYTES + crypto_hash_sha256_BYTES + 1 + 4, sm + crypto_sign_ed25519_BYTES + 5, n - crypto_sign_ed25519_BYTES - 5);

ret = crypto_sign_ed25519_open(m, mlen, buf, buflen, pk);

*mlen = n - 69;
for (i=*mlen; i > 0 ; i--) m[i-1] = sm[i+69-1];

return ret;
}

void sk_ed25519_putsignature(struct buf *b, const unsigned char *x) {

const char *name = "sk-ssh-ed25519@openssh.com";
long long len = crypto_sign_ed25519_BYTES;

buf_putnum32(b, len + str_len(name) + 8 + 1 + 4);
buf_putstring(b, name);
buf_putstringlen(b, x, len);
// put flag and counter
buf_put(b, x+crypto_sign_ed25519_BYTES, 5);
}

void sk_ed25519_putsignpk(struct buf *b, const unsigned char *x) {

const char *name = "sk-ssh-ed25519@openssh.com";
long long len = crypto_sign_ed25519_PUBLICKEYBYTES;

buf_putnum32(b, len + str_len(name) + 16);
buf_putstring(b, name);
buf_putstringlen(b, x, len);
len = str_len(x+crypto_sign_ed25519_PUBLICKEYBYTES);
buf_putstringlen(b, x+crypto_sign_ed25519_PUBLICKEYBYTES, len);
}
void sk_ed25519_putsignpkbase64(struct buf *b, const unsigned char *x) {

unsigned char buf[34 + crypto_sign_ed25519_PUBLICKEYBYTES + 4 + sshcrypto_sign_APPLICATIONMAX];
unsigned application_len = str_len(x+crypto_sign_ed25519_PUBLICKEYBYTES);

byte_copy(buf, 34, "\0\0\0\032sk-ssh-ed25519@openssh.com\0\0\0\040");
byte_copy(buf + 34, crypto_sign_ed25519_PUBLICKEYBYTES, x);
byte_copy(buf + 34 + crypto_sign_ed25519_PUBLICKEYBYTES, 3, "\0\0\0");
buf[34 + crypto_sign_ed25519_PUBLICKEYBYTES + 3] = application_len;
byte_copy(buf + 34 + crypto_sign_ed25519_PUBLICKEYBYTES + 4, application_len, x+crypto_sign_ed25519_PUBLICKEYBYTES);
buf_putbase64(b, buf, 34 + crypto_sign_ed25519_PUBLICKEYBYTES + 4 + application_len);
purge(buf, sizeof buf);
}
int sk_ed25519_parsesignpk(unsigned char *buf, const unsigned char *x, long long xlen) {

long long pos = 0;
crypto_uint32 len;

pos = packetparser_uint32(x, xlen, pos, &len);
pos = packetparser_skip(x, xlen, pos, len);
if (!str_equaln((char *)x + pos - len, len, "sk-ssh-ed25519@openssh.com")) return 0;

// string public key
pos = packetparser_uint32(x, xlen, pos, &len);
if (len != crypto_sign_ed25519_PUBLICKEYBYTES) return 0;
pos = packetparser_copy(x, xlen, pos, buf, len);

// string application (user-specified, but typically "ssh:")
pos = packetparser_uint32(x, xlen, pos, &len);
// only a maximum size of sshcrypto_sign_APPLICATIONMAX allowed
if (len >= sshcrypto_sign_APPLICATIONMAX) return 0;
pos = packetparser_copy(x, xlen, pos, buf+crypto_sign_ed25519_PUBLICKEYBYTES, len);
buf[crypto_sign_ed25519_PUBLICKEYBYTES+len] = '\0';

pos = packetparser_end(x, xlen, pos);
return 1;
}
int sk_ed25519_parsesignature(unsigned char *buf, const unsigned char *x, long long xlen) {

long long pos = 0;
crypto_uint32 len;

pos = packetparser_uint32(x, xlen, pos, &len);
pos = packetparser_skip(x, xlen, pos, len);
if (!str_equaln((char *)x + pos - len, len, "sk-ssh-ed25519@openssh.com")) return 0;

pos = packetparser_uint32(x, xlen, pos, &len);
if (len != crypto_sign_ed25519_BYTES) return 0;
len = len + 5;
pos = packetparser_skip(x, xlen, pos, len);
byte_copy(buf, len, x + pos - len);
pos = packetparser_end(x, xlen, pos);

if ((buf[crypto_sign_ed25519_BYTES] & 0x8) != 0) return 0; // we can't handle extensions yet

return 1;
}
#endif