Enable destination signatures

This commit is contained in:
idk
2019-02-11 23:41:46 -05:00
parent cbcefc71c4
commit 933754748c
12 changed files with 138 additions and 38 deletions

View File

@ -36,3 +36,6 @@ clean:
%.o: %.c Makefile
${CC} ${CFLAGS} -c $< -o $@
fmt:
find . -name '*.c' -exec clang-format -i {} \;
find . -name '*.h' -exec clang-format -i {} \;

View File

@ -1 +1 @@
/home/idk/local-manifest/crypto-manifest/i2p-manifest/libsam3/src/libsam3
../src/libsam3

View File

@ -1,5 +1,7 @@
CFLAGS := -Wall -g -O2 -std=gnu99
all: clean examples
examples: example lookup dclient dserver sclient sserver
example:
@ -9,16 +11,22 @@ lookup:
${CC} ${CFLAGS} namelookup.c -o lookup ../libsam3/libsam3.o
dclient:
${CC} ${CFLAGS} dgramc.c -o datagram-client ../libsam3/libsam3.o
${CC} ${CFLAGS} dgramc.c -o dgramc ../libsam3/libsam3.o
dserver:
${CC} ${CFLAGS} dgrams.c -o datagram-server ../libsam3/libsam3.o
${CC} ${CFLAGS} dgrams.c -o dgrams ../libsam3/libsam3.o
sclient:
${CC} ${CFLAGS} streamc.c -o stream-client ../libsam3/libsam3.o
${CC} ${CFLAGS} streamc.c -o streamc ../libsam3/libsam3.o
sserver:
${CC} ${CFLAGS} streams.c -o stream-server ../libsam3/libsam3.o
${CC} ${CFLAGS} streams.c -o streams ../libsam3/libsam3.o
clean:
rm -f samtest lookup datagram-client datagram-server stream-client stream-server
rm -f samtest lookup dgramc dgrams streamc streams streams.key test-lookup
debug:
sed -i 's|// libsam3_debug = 1;|libsam3_debug = 1;|g' *.c
nodebug:
sed -i 's|libsam3_debug = 1;|// libsam3_debug = 1;|g' *.c

26
examples/sam3/README.md Normal file
View File

@ -0,0 +1,26 @@
Examples
========
These examples show various ways of using libsam3 to enable i2p in your
application, and are also useful in other ways. If you implement an i2p
application library in another language, making variants basic tools wouldn't be
the worst way to make sure that it works.
building
--------
Once you have build the library in the root of this repository by running make
all, you can build all these examples at once by running
make
in this directory. I think it makes things easier to experiment with quickly.
namelookup
----------
Namelookup uses the SAM API to find the base64 destination of an readable "jump"
or base32 i2p address. You can use it like this:
./lookup i2p-projekt.i2p

View File

@ -28,7 +28,7 @@ int main(int argc, char *argv[]) {
char destkey[517] = {0}; // 516 chars + \0
int sz;
//
// libsam3_debug = 1;
libsam3_debug = 1;
//
if (argc < 2) {
FILE *fl = fopen(KEYFILE, "rb");

View File

@ -31,7 +31,7 @@ int main(int argc, char *argv[]) {
FILE *fl;
//
// libsam3_debug = 1;
libsam3_debug = 1;
//
/** generate new destination keypair */

View File

@ -17,14 +17,19 @@
int main(int argc, char *argv[]) {
Sam3Session ses;
//
//
libsam3_debug = 1;
//
if (argc < 2) {
printf("usage: %s name [name...]\n", argv[0]);
return 1;
}
/** for each name in arguments ... */
for (int n = 1; n < argc; ++n) {
fprintf(stdout, "%s ... ", argv[n]);
fflush(stdout);
if (!getenv("I2P_LOOKUP_QUIET")) {
fprintf(stdout, "%s ... ", argv[n]);
fflush(stdout);
}
/** do oneshot name lookup */
if (sam3NameLookup(&ses, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT, argv[n]) >=
0) {

View File

@ -20,6 +20,9 @@ int main(int argc, char *argv[]) {
SAMFieldList *rep = NULL;
const char *v;
//
libsam3_debug = 1;
//
//
if ((fd = sam3Handshake(NULL, 0, NULL)) < 0)
return 1;
//

View File

@ -19,10 +19,11 @@
int main(int argc, char *argv[]) {
Sam3Session ses;
ses.pubcert = 5;
Sam3Connection *conn;
char cmd[1024], destkey[517]; // 516 chars + \0
char cmd[1024], destkey[617]; // 616 chars + \0
//
// libsam3_debug = 1;
libsam3_debug = 1;
//
memset(destkey, 0, sizeof(destkey));
//
@ -30,17 +31,18 @@ int main(int argc, char *argv[]) {
FILE *fl = fopen(KEYFILE, "rb");
//
if (fl != NULL) {
if (fread(destkey, 516, 1, fl) == 1) {
if (fread(destkey, 616, 1, fl) == 1) {
fclose(fl);
goto ok;
}
fclose(fl);
}
printf("usage: dgramc PUBKEY\n");
printf("usage: streamc PUBKEY\n");
return 1;
} else {
if (strlen(argv[1]) != 516) {
fprintf(stderr, "FATAL: invalid key length!\n");
if (!sam3CheckValidKeyLength(argv[1])) {
fprintf(stderr, "FATAL: invalid key length! %s %lu\n", argv[1],
strlen(argv[1]));
return 1;
}
strcpy(destkey, argv[1]);

View File

@ -19,10 +19,11 @@
int main(int argc, char *argv[]) {
Sam3Session ses;
ses.destcert = 5;
Sam3Connection *conn;
FILE *fl;
//
// libsam3_debug = 1;
libsam3_debug = 1;
//
printf("creating session...\n");
// create TRANSIENT session

View File

@ -65,6 +65,14 @@ int sam3tcpSetTimeoutReceive(int fd, int timeoutms) {
return -1;
}
int sam3CheckValidKeyLength(const char *pubkey) {
if (strlen(pubkey) >= SAM3_PUBKEY_SIZE &&
strlen(pubkey) <= SAM3_PUBKEY_SIZE + SAM3_CERT_SIZE) {
return 1;
}
return 0;
}
int sam3tcpConnectIP(uint32_t ip, int port) {
struct sockaddr_in addr;
int fd, val = 1;
@ -640,7 +648,7 @@ size_t sam3GenChannelName(char *dest, size_t minlen, size_t maxlen) {
static int sam3HandshakeInternal(int fd) {
SAMFieldList *rep = NULL;
//
if (sam3tcpPrintf(fd, "HELLO VERSION MIN=3.0 MAX=3.0\n") < 0)
if (sam3tcpPrintf(fd, "HELLO VERSION MIN=3.0 MAX=3.1\n") < 0)
goto error;
rep = sam3ReadReply(fd);
if (!sam3IsGoodReply(rep, "HELLO", "REPLY", "RESULT", "OK"))
@ -679,6 +687,39 @@ static inline void strcpyerr(Sam3Session *ses, const char *errstr) {
strncpy(ses->error, errstr, sizeof(ses->error) - 1);
}
char *getCertType(int type) {
char *certtype;
switch (type) {
case 1:
certtype = "SIGNATURE_TYPE=DSA_SHA1";
break;
case 2:
certtype = "SIGNATURE_TYPE=ECDSA_SHA256_P256";
break;
case 3:
certtype = "SIGNATURE_TYPE=ECDSA_SHA384_P384";
break;
case 4:
certtype = "SIGNATURE_TYPE=ECDSA_SHA512_P521";
break;
case 5:
certtype = "SIGNATURE_TYPE=EdDSA_SHA512_Ed25519";
break;
default:
certtype = "";
break;
}
return certtype;
}
char *sam3GetSessionCertType(Sam3Session *ses) {
return getCertType(ses->pubcert);
}
char *sam3GetConnectionCertType(Sam3Session *ses) {
return getCertType(ses->destcert);
}
int sam3GenerateKeys(Sam3Session *ses, const char *hostname, int port) {
if (ses != NULL) {
SAMFieldList *rep = NULL;
@ -689,14 +730,15 @@ int sam3GenerateKeys(Sam3Session *ses, const char *hostname, int port) {
return -1;
}
//
if (sam3tcpPrintf(fd, "DEST GENERATE\n") >= 0) {
char *buf = sam3GetConnectionCertType(ses);
if (sam3tcpPrintf(fd, "DEST GENERATE %s\n", buf) >= 0) {
if ((rep = sam3ReadReply(fd)) != NULL &&
sam3IsGoodReply(rep, "DEST", "REPLY", NULL, NULL)) {
const char *pub = sam3FindField(rep, "PUB"),
*priv = sam3FindField(rep, "PRIV");
//
if (pub != NULL && strlen(pub) == SAM3_PUBKEY_SIZE && priv != NULL &&
strlen(priv) == SAM3_PRIVKEY_SIZE) {
if (pub != NULL && sam3CheckValidKeyLength(pub) && priv != NULL &&
strlen(priv) == SAM3_PRIVKEY_MIN_SIZE) {
strcpy(ses->pubkey, pub);
strcpy(ses->privkey, priv);
res = 0;
@ -731,7 +773,7 @@ int sam3NameLookup(Sam3Session *ses, const char *hostname, int port,
*pub = sam3FindField(rep, "VALUE");
//
if (strcmp(rs, "OK") == 0) {
if (pub != NULL && strlen(pub) == SAM3_PUBKEY_SIZE) {
if (pub != NULL && sam3CheckValidKeyLength(pub)) {
strcpy(ses->destkey, pub);
strcpyerr(ses, NULL);
res = 0;
@ -809,7 +851,7 @@ int sam3CreateSession(Sam3Session *ses, const char *hostname, int port,
ses->fd = -1;
ses->fwd_fd = -1;
//
if (privkey != NULL && strlen(privkey) != SAM3_PRIVKEY_SIZE)
if (privkey != NULL && strlen(privkey) != SAM3_PRIVKEY_MIN_SIZE)
goto error;
if ((int)type < 0 || (int)type > 2)
goto error;
@ -828,16 +870,17 @@ int sam3CreateSession(Sam3Session *ses, const char *hostname, int port,
if (libsam3_debug)
fprintf(stderr, "sam3CreateSession: creating session (%s)...\n",
typenames[(int)type]);
char *buf = sam3GetSessionCertType(ses);
if (sam3tcpPrintf(ses->fd,
"SESSION CREATE STYLE=%s ID=%s DESTINATION=%s%s%s\n",
typenames[(int)type], ses->channel, privkey, pdel,
"SESSION CREATE STYLE=%s ID=%s DESTINATION=%s %s %s %s\n",
typenames[(int)type], ses->channel, privkey, buf, pdel,
(params != NULL ? params : "")) < 0)
goto error;
if ((rep = sam3ReadReply(ses->fd)) == NULL)
goto error;
if (!sam3IsGoodReply(rep, "SESSION", "STATUS", "RESULT", "OK") ||
(v = sam3FindField(rep, "DESTINATION")) == NULL ||
strlen(v) != SAM3_PRIVKEY_SIZE) {
strlen(v) != SAM3_PRIVKEY_MIN_SIZE) {
if (libsam3_debug)
fprintf(stderr, "sam3CreateSession: invalid reply (%ld)...\n",
(v != NULL ? strlen(v) : -1));
@ -857,7 +900,7 @@ int sam3CreateSession(Sam3Session *ses, const char *hostname, int port,
v = NULL;
if (!sam3IsGoodReply(rep, "NAMING", "REPLY", "RESULT", "OK") ||
(v = sam3FindField(rep, "VALUE")) == NULL ||
strlen(v) != SAM3_PUBKEY_SIZE) {
!sam3CheckValidKeyLength(v)) {
if (libsam3_debug)
fprintf(stderr, "sam3CreateSession: invalid NAMING reply (%ld)...\n",
(v != NULL ? strlen(v) : -1));
@ -891,7 +934,7 @@ Sam3Connection *sam3StreamConnect(Sam3Session *ses, const char *destkey) {
strcpyerr(ses, "INVALID_SESSION");
return NULL;
}
if (destkey == NULL || strlen(destkey) != SAM3_PUBKEY_SIZE) {
if (destkey == NULL || !sam3CheckValidKeyLength(destkey)) {
strcpyerr(ses, "INVALID_KEY");
return NULL;
}
@ -986,7 +1029,7 @@ Sam3Connection *sam3StreamAccept(Sam3Session *ses) {
strcpyerr(ses, (v != NULL && v[0] ? v : "I2P_ERROR_RES1"));
goto error;
}
if (strlen(repstr) != SAM3_PUBKEY_SIZE) {
if (!sam3CheckValidKeyLength(repstr)) {
strcpyerr(ses, "INVALID_KEY");
goto error;
}
@ -1067,7 +1110,7 @@ int sam3DatagramSend(Sam3Session *ses, const char *destkey, const void *buf,
strcpyerr(ses, "INVALID_SESSION");
return -1;
}
if (destkey == NULL || strlen(destkey) != SAM3_PUBKEY_SIZE) {
if (destkey == NULL || !sam3CheckValidKeyLength(destkey)) {
strcpyerr(ses, "INVALID_KEY");
return -1;
}
@ -1075,7 +1118,7 @@ int sam3DatagramSend(Sam3Session *ses, const char *destkey, const void *buf,
strcpyerr(ses, "INVALID_DATA");
return -1;
}
dbufsz = bufsize + 4 + 517 + strlen(ses->channel) + 1;
dbufsz = bufsize + 4 + SAM3_PUBKEY_SIZE + 1 + strlen(ses->channel) + 1;
if ((dbuf = malloc(dbufsz)) == NULL) {
strcpyerr(ses, "OUT_OF_MEMORY");
return -1;
@ -1119,7 +1162,7 @@ ssize_t sam3DatagramReceive(Sam3Session *ses, void *buf, size_t bufsize) {
}
//
if ((v = sam3FindField(rep, "DESTINATION")) != NULL &&
strlen(v) == SAM3_PUBKEY_SIZE)
sam3CheckValidKeyLength(v))
strncpy(ses->destkey, v, sizeof(ses->destkey));
v = sam3FindField(rep, "SIZE"); // we have this field -- for sure
if (!v[0] || !isdigit(*v)) {

View File

@ -28,7 +28,7 @@ extern int libsam3_debug;
#define SAM3_PUBKEY_SIZE (516)
#define SAM3_CERT_SIZE (100)
#define SAM3_PRIVKEY_SIZE (884)
#define SAM3_PRIVKEY_MIN_SIZE (884)
////////////////////////////////////////////////////////////////////////////////
/* returns fd or -1 */
@ -117,14 +117,15 @@ typedef enum {
typedef struct Sam3Session {
Sam3SessionType type;
int fd;
char privkey[SAM3_PRIVKEY_SIZE + 1]; // destination private key (asciiz)
char privkey[SAM3_PRIVKEY_MIN_SIZE + 1]; // destination private key (asciiz)
char pubkey[SAM3_PUBKEY_SIZE + SAM3_CERT_SIZE +
1]; // destination public key (asciiz)
// char cert[SAM3_CERT_SIZE+1]
int pubcert;
char channel[66]; // name of this sam session (asciiz)
char destkey[SAM3_PUBKEY_SIZE + SAM3_CERT_SIZE +
1]; // for DGRAM sessions (asciiz)
char error[32]; // error message (asciiz)
int destcert;
char error[32]; // error message (asciiz)
uint32_t ip;
int port; // this will be changed to UDP port for DRAM/RAW (can be 0)
struct Sam3Connection *connlist; // list of opened connections
@ -135,8 +136,10 @@ typedef struct Sam3Connection {
Sam3Session *ses;
struct Sam3Connection *next;
int fd;
char destkey[SAM3_PUBKEY_SIZE + 1]; // remote destination public key (asciiz)
char error[32]; // error message (asciiz)
char destkey[SAM3_PUBKEY_SIZE + SAM3_CERT_SIZE +
1]; // remote destination public key (asciiz)
int destcert;
char error[32]; // error message (asciiz)
} Sam3Connection;
////////////////////////////////////////////////////////////////////////////////
@ -162,6 +165,12 @@ extern int sam3CreateSession(Sam3Session *ses, const char *hostname, int port,
*/
extern int sam3CloseSession(Sam3Session *ses);
/*
* Check to make sure that the destination in use is of a valid length, returns
* 1 if true and 0 if false.
*/
int sam3CheckValidKeyLength(const char *pubkey);
/*
* open stream connection to 'destkey' endpoint
* 'destkey' is 516-byte public key (asciiz)