|
@@ -0,0 +1,791 @@
|
|
|
+diff --git a/admin/AuthorizedPasswords.c b/admin/AuthorizedPasswords.c
|
|
|
+index addc04d..9982458 100644
|
|
|
+--- a/admin/AuthorizedPasswords.c
|
|
|
++++ b/admin/AuthorizedPasswords.c
|
|
|
+@@ -38,10 +38,9 @@ static void add(Dict* args, void* vcontext, String* txid, struct Allocator* allo
|
|
|
+
|
|
|
+ String* passwd = Dict_getString(args, String_CONST("password"));
|
|
|
+ String* user = Dict_getString(args, String_CONST("user"));
|
|
|
+- String* displayName = Dict_getString(args, String_CONST("displayName"));
|
|
|
+ String* ipv6 = Dict_getString(args, String_CONST("ipv6"));
|
|
|
+
|
|
|
+- int32_t ret = CryptoAuth_addUser_ipv6(passwd, user, displayName, ipv6, context->ca);
|
|
|
++ int32_t ret = CryptoAuth_addUser_ipv6(passwd, user, ipv6, context->ca);
|
|
|
+
|
|
|
+ switch (ret) {
|
|
|
+ case 0:
|
|
|
+@@ -51,10 +50,6 @@ static void add(Dict* args, void* vcontext, String* txid, struct Allocator* allo
|
|
|
+ sendResponse(String_CONST("Specified auth type is not supported."),
|
|
|
+ context->admin, txid, alloc);
|
|
|
+ break;
|
|
|
+- case CryptoAuth_addUser_OUT_OF_SPACE:
|
|
|
+- sendResponse(String_CONST("Out of memory to store password."),
|
|
|
+- context->admin, txid, alloc);
|
|
|
+- break;
|
|
|
+ case CryptoAuth_addUser_DUPLICATE:
|
|
|
+ sendResponse(String_CONST("Password already added."), context->admin, txid, alloc);
|
|
|
+ break;
|
|
|
+@@ -110,7 +105,6 @@ void AuthorizedPasswords_init(struct Admin* admin,
|
|
|
+ Admin_registerFunction("AuthorizedPasswords_add", add, context, true,
|
|
|
+ ((struct Admin_FunctionArg[]){
|
|
|
+ { .name = "password", .required = 1, .type = "String" },
|
|
|
+- { .name = "displayName", .required = 0, .type = "String" },
|
|
|
+ { .name = "ipv6", .required = 0, .type = "String" },
|
|
|
+ { .name = "user", .required = 0, .type = "String" }
|
|
|
+ }), admin);
|
|
|
+diff --git a/crypto/CryptoAuth.c b/crypto/CryptoAuth.c
|
|
|
+index 858a429..6ae6a3f 100644
|
|
|
+--- a/crypto/CryptoAuth.c
|
|
|
++++ b/crypto/CryptoAuth.c
|
|
|
+@@ -111,47 +111,25 @@ static inline void getSharedSecret(uint8_t outputSecret[32],
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+-static inline void hashPassword_sha256(struct CryptoAuth_Auth* auth, const String* password)
|
|
|
++static inline void hashPassword(uint8_t secretOut[32],
|
|
|
++ union CryptoHeader_Challenge* challengeOut,
|
|
|
++ const String* login,
|
|
|
++ const String* password,
|
|
|
++ const uint8_t authType)
|
|
|
+ {
|
|
|
++ crypto_hash_sha256(secretOut, (uint8_t*) password->bytes, password->len);
|
|
|
+ uint8_t tempBuff[32];
|
|
|
+- crypto_hash_sha256(auth->secret, (uint8_t*) password->bytes, password->len);
|
|
|
+- crypto_hash_sha256(tempBuff, auth->secret, 32);
|
|
|
+- Bits_memcpyConst(auth->challenge.bytes, tempBuff, CryptoHeader_Challenge_SIZE);
|
|
|
+- CryptoHeader_setAuthChallengeDerivations(&auth->challenge, 0);
|
|
|
+- auth->challenge.challenge.type = 1;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static inline void hashPassword_withLogin(struct CryptoAuth_Auth* auth,
|
|
|
+- const String* login,
|
|
|
+- const String* password)
|
|
|
+-{
|
|
|
+- crypto_hash_sha256(auth->secret, (uint8_t*) password->bytes, password->len);
|
|
|
+- uint8_t tempBuff[32];
|
|
|
+- crypto_hash_sha256(tempBuff, (uint8_t*) login->bytes, login->len);
|
|
|
+- Bits_memcpyConst(auth->challenge.bytes, tempBuff, CryptoHeader_Challenge_SIZE);
|
|
|
+- CryptoHeader_setAuthChallengeDerivations(&auth->challenge, 0);
|
|
|
+- auth->challenge.challenge.type = 2;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static inline uint8_t* hashPassword(struct CryptoAuth_Auth* auth,
|
|
|
+- const String* login,
|
|
|
+- const String* password,
|
|
|
+- const uint8_t authType)
|
|
|
+-{
|
|
|
+- switch (authType) {
|
|
|
+- case 1: {
|
|
|
+- hashPassword_sha256(auth, password);
|
|
|
+- break;
|
|
|
+- }
|
|
|
+- case 2: {
|
|
|
+- Assert_true(login);
|
|
|
+- hashPassword_withLogin(auth, login, password);
|
|
|
+- break;
|
|
|
+- }
|
|
|
+- default:
|
|
|
+- Assert_failure("Unsupported auth type.");
|
|
|
+- };
|
|
|
+- return auth->secret;
|
|
|
++ if (authType == 1) {
|
|
|
++ crypto_hash_sha256(tempBuff, secretOut, 32);
|
|
|
++ } else if (authType == 2) {
|
|
|
++ crypto_hash_sha256(tempBuff, (uint8_t*) login->bytes, login->len);
|
|
|
++ } else {
|
|
|
++ Assert_failure("Unsupported auth type [%u]", authType);
|
|
|
++ }
|
|
|
++ Bits_memcpyConst(challengeOut->bytes, tempBuff, CryptoHeader_Challenge_SIZE);
|
|
|
++ CryptoHeader_setAuthChallengeDerivations(challengeOut, 0);
|
|
|
++ challengeOut->challenge.type = authType;
|
|
|
++ challengeOut->challenge.additional = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+@@ -161,22 +139,29 @@ static inline uint8_t* hashPassword(struct CryptoAuth_Auth* auth,
|
|
|
+ * @param context the CryptoAuth engine to search in.
|
|
|
+ * @return an Auth struct with a if one is found, otherwise NULL.
|
|
|
+ */
|
|
|
+-static inline struct CryptoAuth_Auth* getAuth(union CryptoHeader_Challenge auth,
|
|
|
+- struct CryptoAuth_pvt* context)
|
|
|
++static inline struct CryptoAuth_User* getAuth(union CryptoHeader_Challenge* auth,
|
|
|
++ struct CryptoAuth_pvt* ca)
|
|
|
+ {
|
|
|
+- if (auth.challenge.type != 1) {
|
|
|
++ if (auth->challenge.type == 0) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+- for (uint32_t i = 0; i < context->passwordCount; i++) {
|
|
|
+- if (Bits_memcmp(auth.bytes, &context->passwords[i], CryptoHeader_Challenge_KEYSIZE) == 0) {
|
|
|
+- return &context->passwords[i];
|
|
|
++ int count = 0;
|
|
|
++ for (struct CryptoAuth_User* u = ca->users; u; u = u->next) {
|
|
|
++ count++;
|
|
|
++ if (auth->challenge.type == 1 &&
|
|
|
++ !Bits_memcmp(auth->bytes, u->passwordHash, CryptoHeader_Challenge_KEYSIZE))
|
|
|
++ {
|
|
|
++ return u;
|
|
|
++ } else if (auth->challenge.type == 2 &&
|
|
|
++ !Bits_memcmp(auth->bytes, u->userNameHash, CryptoHeader_Challenge_KEYSIZE))
|
|
|
++ {
|
|
|
++ return u;
|
|
|
+ }
|
|
|
+ }
|
|
|
+- Log_debug(context->logger, "Got unrecognized auth, password count = [%d]",
|
|
|
+- context->passwordCount);
|
|
|
++ Log_debug(ca->logger, "Got unrecognized auth, password count = [%d]", count);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+-
|
|
|
++/*
|
|
|
+ static inline uint8_t* tryAuth(union CryptoHeader* cauth,
|
|
|
+ uint8_t hashOutput[32],
|
|
|
+ struct CryptoAuth_Session_pvt* session,
|
|
|
+@@ -191,7 +176,7 @@ static inline uint8_t* tryAuth(union CryptoHeader* cauth,
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+-
|
|
|
++*/
|
|
|
+ /**
|
|
|
+ * Decrypt and authenticate.
|
|
|
+ *
|
|
|
+@@ -383,15 +368,18 @@ static void encryptHandshake(struct Message* message,
|
|
|
+
|
|
|
+ // Password auth
|
|
|
+ uint8_t* passwordHash = NULL;
|
|
|
+- struct CryptoAuth_Auth auth;
|
|
|
++ uint8_t passwordHashStore[32];
|
|
|
+ if (session->password != NULL) {
|
|
|
+- passwordHash = hashPassword(&auth, session->login, session->password, session->authType);
|
|
|
+- Bits_memcpyConst(header->handshake.auth.bytes,
|
|
|
+- &auth.challenge,
|
|
|
+- sizeof(union CryptoHeader_Challenge));
|
|
|
++ hashPassword(passwordHashStore,
|
|
|
++ &header->handshake.auth,
|
|
|
++ session->login,
|
|
|
++ session->password,
|
|
|
++ session->authType);
|
|
|
++ passwordHash = passwordHashStore;
|
|
|
++ } else {
|
|
|
++ header->handshake.auth.challenge.type = session->authType;
|
|
|
++ header->handshake.auth.challenge.additional = 0;
|
|
|
+ }
|
|
|
+- header->handshake.auth.challenge.type = session->authType;
|
|
|
+- header->handshake.auth.challenge.additional = 0;
|
|
|
+
|
|
|
+ // Set the session state
|
|
|
+ header->nonce = Endian_hostToBigEndian32(session->nextNonce);
|
|
|
+@@ -599,26 +587,24 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+- String* user = NULL;
|
|
|
+- struct CryptoAuth_Auth* auth = NULL;
|
|
|
+- uint8_t passwordHashStore[32];
|
|
|
+- uint8_t* passwordHash = tryAuth(header, passwordHashStore, session, &auth);
|
|
|
++ struct CryptoAuth_User* userObj = getAuth(&header->handshake.auth, session->context);
|
|
|
+ uint8_t* restrictedToip6 = NULL;
|
|
|
+- if (auth) {
|
|
|
+- user = auth->user;
|
|
|
+- if (auth->restrictedToip6) {
|
|
|
+- restrictedToip6 = auth->restrictedToip6;
|
|
|
+- if (!ip6MatchesKey(auth->restrictedToip6, header->handshake.publicKey)) {
|
|
|
++ uint8_t* passwordHash = NULL;
|
|
|
++ if (userObj) {
|
|
|
++ passwordHash = userObj->secret;
|
|
|
++ if (userObj->restrictedToip6[0]) {
|
|
|
++ restrictedToip6 = userObj->restrictedToip6;
|
|
|
++ if (!ip6MatchesKey(restrictedToip6, header->handshake.publicKey)) {
|
|
|
+ cryptoAuthDebug0(session, "DROP packet with key not matching restrictedToip6");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+- if (session->requireAuth && !user) {
|
|
|
++ if (session->requireAuth && !userObj) {
|
|
|
+ cryptoAuthDebug0(session, "DROP message because auth was not given");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+- if (passwordHash == NULL && header->handshake.auth.challenge.type != 0) {
|
|
|
++ if (!userObj && header->handshake.auth.challenge.type != 0) {
|
|
|
+ cryptoAuthDebug0(session, "DROP message with unrecognized authenticator");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+@@ -632,7 +618,7 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
|
|
|
+ if (nonce < 2) {
|
|
|
+ if (nonce == 0) {
|
|
|
+ cryptoAuthDebug(session, "Received a hello packet, using auth: %d",
|
|
|
+- (passwordHash != NULL));
|
|
|
++ (userObj != NULL));
|
|
|
+ } else {
|
|
|
+ cryptoAuthDebug0(session, "Received a repeat hello packet");
|
|
|
+ }
|
|
|
+@@ -641,7 +627,8 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
|
|
|
+ if (!knowHerKey(session) || session->nextNonce == 0) {
|
|
|
+ herPermKey = header->handshake.publicKey;
|
|
|
+ if (Defined(Log_DEBUG) && Bits_isZero(header->handshake.publicKey, 32)) {
|
|
|
+- cryptoAuthDebug0(session, "Node sent public key of ZERO!");
|
|
|
++ cryptoAuthDebug0(session, "DROP Node sent public key of ZERO!");
|
|
|
++ return -1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ herPermKey = session->pub.herPublicKey;
|
|
|
+@@ -663,7 +650,8 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
|
|
|
+ } else if (nonce == 3) {
|
|
|
+ cryptoAuthDebug0(session, "Received a repeat key packet");
|
|
|
+ } else {
|
|
|
+- cryptoAuthDebug(session, "Received a packet of unknown type! nonce=%u", nonce);
|
|
|
++ cryptoAuthDebug(session, "DROP Received a packet of unknown type! nonce=%u", nonce);
|
|
|
++ return -1;
|
|
|
+ }
|
|
|
+ if (Bits_memcmp(header->handshake.publicKey, session->pub.herPublicKey, 32)) {
|
|
|
+ cryptoAuthDebug0(session, "DROP packet contains different perminent key");
|
|
|
+@@ -710,6 +698,7 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
|
|
|
+
|
|
|
+ if (Bits_isZero(header->handshake.encryptedTempKey, 32)) {
|
|
|
+ // we need to reject 0 public keys outright because they will be confused with "unknown"
|
|
|
++ cryptoAuthDebug0(session, "DROP message with zero as temp public key");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -735,6 +724,7 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
|
|
|
+ } else if (nonce == 2 && session->nextNonce >= 4) {
|
|
|
+ // we accept a new key packet and let it change the session since the other end might have
|
|
|
+ // killed off the session while it was in the midst of setting up.
|
|
|
++ // This is NOT a repeat key packet because it's nonce is 2, not 3
|
|
|
+ if (!Bits_memcmp(session->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
|
|
|
+ Assert_true(!Bits_isZero(session->herTempPubKey, 32));
|
|
|
+ cryptoAuthDebug0(session, "DROP dupe key packet with same temp key");
|
|
|
+@@ -760,12 +750,6 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
|
|
|
+ if (nextNonce == 4) {
|
|
|
+ if (session->nextNonce <= 4) {
|
|
|
+ // and have not yet begun sending "run" data
|
|
|
+- Assert_true(session->nextNonce <= nextNonce);
|
|
|
+- session->nextNonce = nextNonce;
|
|
|
+-
|
|
|
+- if (!session->pub.displayName) {
|
|
|
+- session->pub.displayName = user;
|
|
|
+- }
|
|
|
+ Bits_memcpyConst(session->herTempPubKey, header->handshake.encryptedTempKey, 32);
|
|
|
+ } else {
|
|
|
+ // It's a (possibly repeat) key packet and we have begun sending run data.
|
|
|
+@@ -776,6 +760,7 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
|
|
|
+ header->handshake.encryptedTempKey,
|
|
|
+ NULL,
|
|
|
+ session->context->logger);
|
|
|
++ nextNonce = session->nextNonce + 1;
|
|
|
+ cryptoAuthDebug0(session, "New key packet but we are already sending data");
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -802,14 +787,6 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
|
|
|
+ nextNonce = 3;
|
|
|
+ }
|
|
|
+
|
|
|
+- Assert_true(session->nextNonce <= nextNonce);
|
|
|
+- session->nextNonce = nextNonce;
|
|
|
+- if (!session->pub.displayName) {
|
|
|
+- session->pub.displayName = user;
|
|
|
+- }
|
|
|
+- if (restrictedToip6) {
|
|
|
+- Bits_memcpyConst(session->pub.herIp6, restrictedToip6, 16);
|
|
|
+- }
|
|
|
+ Bits_memcpyConst(session->herTempPubKey, header->handshake.encryptedTempKey, 32);
|
|
|
+
|
|
|
+ } else if (Bits_memcmp(header->handshake.publicKey, session->context->pub.publicKey, 32) < 0) {
|
|
|
+@@ -819,23 +796,28 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
|
|
|
+ cryptoAuthDebug0(session, "Incoming hello from node with lower key, resetting");
|
|
|
+ reset(session);
|
|
|
+
|
|
|
+- Assert_true(session->nextNonce <= nextNonce);
|
|
|
+- session->nextNonce = nextNonce;
|
|
|
+- if (!session->pub.displayName) {
|
|
|
+- session->pub.displayName = user;
|
|
|
+- }
|
|
|
+- if (restrictedToip6) {
|
|
|
+- Bits_memcpyConst(session->pub.herIp6, restrictedToip6, 16);
|
|
|
+- }
|
|
|
+ Bits_memcpyConst(session->herTempPubKey, header->handshake.encryptedTempKey, 32);
|
|
|
+
|
|
|
+ } else {
|
|
|
+- cryptoAuthDebug0(session, "Incoming hello from node with higher key, not resetting");
|
|
|
++ cryptoAuthDebug0(session, "DROP Incoming hello from node with higher key, not resetting");
|
|
|
++ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (herPermKey && herPermKey != session->pub.herPublicKey) {
|
|
|
+ Bits_memcpyConst(session->pub.herPublicKey, herPermKey, 32);
|
|
|
+ }
|
|
|
++ if (!session->pub.displayName && userObj) {
|
|
|
++ session->pub.displayName = userObj->login;
|
|
|
++ }
|
|
|
++ if (restrictedToip6) {
|
|
|
++ Bits_memcpyConst(session->pub.herIp6, restrictedToip6, 16);
|
|
|
++ }
|
|
|
++
|
|
|
++ // Nonces can never go backward and can only "not advance" if they're 0,1,2,3 session state.
|
|
|
++ Assert_true(session->nextNonce < nextNonce ||
|
|
|
++ (session->nextNonce <= 4 && nextNonce == session->nextNonce)
|
|
|
++ );
|
|
|
++ session->nextNonce = nextNonce;
|
|
|
+
|
|
|
+ Bits_memset(&session->pub.replayProtector, 0, sizeof(struct ReplayProtector));
|
|
|
+
|
|
|
+@@ -936,9 +918,6 @@ struct CryptoAuth* CryptoAuth_new(struct Allocator* allocator,
|
|
|
+ struct CryptoAuth_pvt* ca = Allocator_calloc(allocator, sizeof(struct CryptoAuth_pvt), 1);
|
|
|
+ Identity_set(ca);
|
|
|
+ ca->allocator = allocator;
|
|
|
+- ca->passwords = Allocator_calloc(allocator, sizeof(struct CryptoAuth_Auth), 232);
|
|
|
+- ca->passwordCount = 0;
|
|
|
+- ca->passwordCapacity = 232;
|
|
|
+ ca->eventBase = eventBase;
|
|
|
+ ca->logger = logger;
|
|
|
+ ca->pub.resetAfterInactivitySeconds = CryptoAuth_DEFAULT_RESET_AFTER_INACTIVITY_SECONDS;
|
|
|
+@@ -965,87 +944,93 @@ struct CryptoAuth* CryptoAuth_new(struct Allocator* allocator,
|
|
|
+ return &ca->pub;
|
|
|
+ }
|
|
|
+
|
|
|
+-int32_t CryptoAuth_addUser(String* password,
|
|
|
+- String* login,
|
|
|
+- String* displayName,
|
|
|
+- struct CryptoAuth* ca)
|
|
|
++int CryptoAuth_addUser_ipv6(String* password,
|
|
|
++ String* login,
|
|
|
++ String* ipv6,
|
|
|
++ struct CryptoAuth* cryptoAuth)
|
|
|
+ {
|
|
|
+- return CryptoAuth_addUser_ipv6(password, login, displayName, NULL, ca);
|
|
|
+-}
|
|
|
++ struct CryptoAuth_pvt* ca = Identity_check((struct CryptoAuth_pvt*) cryptoAuth);
|
|
|
+
|
|
|
+-int32_t CryptoAuth_addUser_ipv6(String* password,
|
|
|
+- String* login,
|
|
|
+- String* displayName,
|
|
|
+- String* ipv6,
|
|
|
+- struct CryptoAuth* ca)
|
|
|
+-{
|
|
|
+- struct CryptoAuth_pvt* context = Identity_check((struct CryptoAuth_pvt*) ca);
|
|
|
++ struct Allocator* alloc = Allocator_child(ca->allocator);
|
|
|
++ struct CryptoAuth_User* user = Allocator_calloc(alloc, sizeof(struct CryptoAuth_User), 1);
|
|
|
++ user->alloc = alloc;
|
|
|
++ Identity_set(user);
|
|
|
+
|
|
|
+- struct CryptoAuth_Auth a;
|
|
|
+- if (login) {
|
|
|
+- hashPassword_withLogin(&a, login, password);
|
|
|
++ if (!login) {
|
|
|
++ int i = 0;
|
|
|
++ for (struct CryptoAuth_User* u = ca->users; u; u = u->next) { i++; }
|
|
|
++ user->login = login = String_printf(alloc, "Anon #%d", i);
|
|
|
+ } else {
|
|
|
+- hashPassword_sha256(&a, password);
|
|
|
++ user->login = String_clone(login, alloc);
|
|
|
+ }
|
|
|
+- for (uint32_t i = 0; i < context->passwordCount; i++) {
|
|
|
+- if (!Bits_memcmp(a.secret, context->passwords[i].secret, 32) ||
|
|
|
+- String_equals(displayName, context->passwords[i].user))
|
|
|
+- {
|
|
|
++
|
|
|
++ union CryptoHeader_Challenge ac;
|
|
|
++ // Users specified with a login field might want to use authType 1 still.
|
|
|
++ hashPassword(user->secret, &ac, login, password, 2);
|
|
|
++ Bits_memcpyConst(user->userNameHash, ac.bytes, 8);
|
|
|
++ hashPassword(user->secret, &ac, NULL, password, 1);
|
|
|
++ Bits_memcpyConst(user->passwordHash, ac.bytes, 8);
|
|
|
++
|
|
|
++ for (struct CryptoAuth_User* u = ca->users; u; u = u->next) {
|
|
|
++ if (Bits_memcmp(user->secret, u->secret, 32)) {
|
|
|
++ } else if (!login) {
|
|
|
++ } else if (String_equals(login, u->login)) {
|
|
|
++ Allocator_free(alloc);
|
|
|
+ return CryptoAuth_addUser_DUPLICATE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+- a.user = String_clone(displayName, context->allocator);
|
|
|
++
|
|
|
+ if (ipv6) {
|
|
|
+- // TODO(cjd): This could become a memory leak
|
|
|
+- a.restrictedToip6 = Allocator_malloc(context->allocator, 16);
|
|
|
+- if (AddrTools_parseIp(a.restrictedToip6, ipv6->bytes) < 0) {
|
|
|
+- Log_debug(context->logger, "Ipv6 parsing error!");
|
|
|
++ if (AddrTools_parseIp(user->restrictedToip6, ipv6->bytes) < 0) {
|
|
|
++ Log_debug(ca->logger, "Ipv6 parsing error!");
|
|
|
++ Allocator_free(alloc);
|
|
|
+ return CryptoAuth_addUser_INVALID_IP;
|
|
|
+ }
|
|
|
+- } else {
|
|
|
+- a.restrictedToip6 = NULL;
|
|
|
+ }
|
|
|
+- Bits_memcpyConst(&context->passwords[context->passwordCount],
|
|
|
+- &a,
|
|
|
+- sizeof(struct CryptoAuth_Auth));
|
|
|
+- context->passwordCount++;
|
|
|
++
|
|
|
++ // Add the user to the *end* of the list
|
|
|
++ for (struct CryptoAuth_User** up = &ca->users; ; up = &(*up)->next) {
|
|
|
++ if (!*up) {
|
|
|
++ *up = user;
|
|
|
++ break;
|
|
|
++ }
|
|
|
++ }
|
|
|
++
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+-int CryptoAuth_removeUsers(struct CryptoAuth* context, String* user)
|
|
|
++int CryptoAuth_removeUsers(struct CryptoAuth* context, String* login)
|
|
|
+ {
|
|
|
+- struct CryptoAuth_pvt* ctx = Identity_check((struct CryptoAuth_pvt*) context);
|
|
|
+- if (!user) {
|
|
|
+- int count = ctx->passwordCount;
|
|
|
+- Log_debug(ctx->logger, "Flushing [%d] users", count);
|
|
|
+- ctx->passwordCount = 0;
|
|
|
+- return count;
|
|
|
+- }
|
|
|
++ struct CryptoAuth_pvt* ca = Identity_check((struct CryptoAuth_pvt*) context);
|
|
|
++
|
|
|
+ int count = 0;
|
|
|
+- int i = 0;
|
|
|
+- while (i < (int)ctx->passwordCount) {
|
|
|
+- if (String_equals(ctx->passwords[i].user, user)) {
|
|
|
+- Bits_memcpyConst(&ctx->passwords[i],
|
|
|
+- &ctx->passwords[ctx->passwordCount--],
|
|
|
+- sizeof(struct CryptoAuth_Auth));
|
|
|
++ struct CryptoAuth_User** up = &ca->users;
|
|
|
++ struct CryptoAuth_User* u = *up;
|
|
|
++ while ((u = *up)) {
|
|
|
++ if (!login || String_equals(login, u->login)) {
|
|
|
++ *up = u->next;
|
|
|
++ Allocator_free(u->alloc);
|
|
|
+ count++;
|
|
|
+ } else {
|
|
|
+- i++;
|
|
|
++ up = &u->next;
|
|
|
+ }
|
|
|
+ }
|
|
|
+- Log_debug(ctx->logger, "Removing [%d] user(s) identified by [%s]", count, user->bytes);
|
|
|
++
|
|
|
++ if (!login) {
|
|
|
++ Log_debug(ca->logger, "Flushing [%d] users", count);
|
|
|
++ } else {
|
|
|
++ Log_debug(ca->logger, "Removing [%d] user(s) identified by [%s]", count, login->bytes);
|
|
|
++ }
|
|
|
+ return count;
|
|
|
+ }
|
|
|
+
|
|
|
+ List* CryptoAuth_getUsers(struct CryptoAuth* context, struct Allocator* alloc)
|
|
|
+ {
|
|
|
+- struct CryptoAuth_pvt* ctx = Identity_check((struct CryptoAuth_pvt*) context);
|
|
|
+- uint32_t count = ctx->passwordCount;
|
|
|
++ struct CryptoAuth_pvt* ca = Identity_check((struct CryptoAuth_pvt*) context);
|
|
|
+
|
|
|
+ List* users = List_new(alloc);
|
|
|
+-
|
|
|
+- for (uint32_t i = 0; i < count; i++) {
|
|
|
+- List_addString(users, String_clone(ctx->passwords[i].user, alloc), alloc);
|
|
|
++ for (struct CryptoAuth_User* u = ca->users; u; u = u->next) {
|
|
|
++ List_addString(users, String_clone(u->login, alloc), alloc);
|
|
|
+ }
|
|
|
+
|
|
|
+ return users;
|
|
|
+diff --git a/crypto/CryptoAuth.h b/crypto/CryptoAuth.h
|
|
|
+index 148326e..b6aefdf 100644
|
|
|
+--- a/crypto/CryptoAuth.h
|
|
|
++++ b/crypto/CryptoAuth.h
|
|
|
+@@ -74,24 +74,21 @@ struct CryptoAuth_Session
|
|
|
+ * @param context The CryptoAuth context.
|
|
|
+ * @return 0 if all goes well,
|
|
|
+ * CryptoAuth_addUser_INVALID_AUTHTYPE if the authentication method is not supported,
|
|
|
+- * CryptoAuth_addUser_OUT_OF_SPACE if there is not enough space to store the entry,
|
|
|
+ * CryptoAuth_addUser_DUPLICATE if the same *password* already exists.
|
|
|
+ * CryptoAuth_addUser_INVALID_IP if the ipv6 is not valid.
|
|
|
+ */
|
|
|
+ #define CryptoAuth_addUser_INVALID_AUTHTYPE -1
|
|
|
+-#define CryptoAuth_addUser_OUT_OF_SPACE -2
|
|
|
+ #define CryptoAuth_addUser_DUPLICATE -3
|
|
|
+ #define CryptoAuth_addUser_INVALID_IP -4
|
|
|
+-int32_t CryptoAuth_addUser_ipv6(String* password,
|
|
|
+- String* login,
|
|
|
+- String* displayName,
|
|
|
+- String* ipv6,
|
|
|
+- struct CryptoAuth* ca);
|
|
|
+-
|
|
|
+-int32_t CryptoAuth_addUser(String* password,
|
|
|
+- String* login,
|
|
|
+- String* displayName,
|
|
|
+- struct CryptoAuth* ca);
|
|
|
++int CryptoAuth_addUser_ipv6(String* password,
|
|
|
++ String* login,
|
|
|
++ String* ipv6,
|
|
|
++ struct CryptoAuth* ca);
|
|
|
++
|
|
|
++static inline int CryptoAuth_addUser(String* password, String* login, struct CryptoAuth* ca)
|
|
|
++{
|
|
|
++ return CryptoAuth_addUser_ipv6(password, login, NULL, ca);
|
|
|
++}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Remove all users registered with this CryptoAuth.
|
|
|
+diff --git a/crypto/CryptoAuth_pvt.h b/crypto/CryptoAuth_pvt.h
|
|
|
+index b57b2c0..def7fad 100644
|
|
|
+--- a/crypto/CryptoAuth_pvt.h
|
|
|
++++ b/crypto/CryptoAuth_pvt.h
|
|
|
+@@ -26,13 +26,25 @@
|
|
|
+
|
|
|
+ #include <stdint.h>
|
|
|
+
|
|
|
+-struct CryptoAuth_Auth {
|
|
|
+- union CryptoHeader_Challenge challenge;
|
|
|
++struct CryptoAuth_User;
|
|
|
++struct CryptoAuth_User {
|
|
|
++ /** Double-hash of password for authType 1 */
|
|
|
++ uint8_t passwordHash[8];
|
|
|
++
|
|
|
++ /** Hash of username for authType 2 */
|
|
|
++ uint8_t userNameHash[8];
|
|
|
+
|
|
|
+ uint8_t secret[32];
|
|
|
+
|
|
|
+- String* user;
|
|
|
+- uint8_t* restrictedToip6;
|
|
|
++ String* login;
|
|
|
++
|
|
|
++ uint8_t restrictedToip6[16];
|
|
|
++
|
|
|
++ struct CryptoAuth_User* next;
|
|
|
++
|
|
|
++ struct Allocator* alloc;
|
|
|
++
|
|
|
++ Identity
|
|
|
+ };
|
|
|
+
|
|
|
+ struct CryptoAuth_pvt
|
|
|
+@@ -41,9 +53,7 @@ struct CryptoAuth_pvt
|
|
|
+
|
|
|
+ uint8_t privateKey[32];
|
|
|
+
|
|
|
+- struct CryptoAuth_Auth* passwords;
|
|
|
+- uint32_t passwordCount;
|
|
|
+- uint32_t passwordCapacity;
|
|
|
++ struct CryptoAuth_User* users;
|
|
|
+
|
|
|
+ struct Log* logger;
|
|
|
+ struct EventBase* eventBase;
|
|
|
+diff --git a/crypto/test/CryptoAuth_test.c b/crypto/test/CryptoAuth_test.c
|
|
|
+index 23492f1..dc73e1a 100644
|
|
|
+--- a/crypto/test/CryptoAuth_test.c
|
|
|
++++ b/crypto/test/CryptoAuth_test.c
|
|
|
+@@ -24,13 +24,15 @@
|
|
|
+ #include "util/log/FileWriterLog.h"
|
|
|
+ #include "wire/CryptoHeader.h"
|
|
|
+
|
|
|
+-#define PRIVATEKEY ( \
|
|
|
+- "\x20\xca\x45\xd9\x5b\xbf\xca\xe7\x35\x3c\xd2\xdf\xfa\x12\x84\x4b" \
|
|
|
+- "\x4e\xff\xbe\x7d\x39\xd8\x4d\x8e\x14\x2b\x9d\x21\x89\x5b\x38\x09" )
|
|
|
++#define PRIVATEKEY_A \
|
|
|
++ Constant_stringForHex("53ff22b2eb94ce8c5f1852c0f557eb901f067e5273d541e0a21e143c20dff9da")
|
|
|
++#define PUBLICKEY_A \
|
|
|
++ Constant_stringForHex("e3ff75af6e4414494df22f200ffeaa56e7976d991d33cc87f52427e27f83235d")
|
|
|
+
|
|
|
+-#define PUBLICKEY ( \
|
|
|
+- "\x51\xaf\x8d\xd9\x35\xe8\x61\x86\x3e\x94\x2b\x1b\x6d\x21\x22\xe0" \
|
|
|
+- "\x2f\xb2\xd0\x88\x20\xbb\xf3\xf0\x6f\xcd\xe5\x85\x30\xe0\x08\x34" )
|
|
|
++#define PRIVATEKEY_B \
|
|
|
++ Constant_stringForHex("b71c4f43e3d4b1879b5065d44a1cb43eaf07ddba96de6a72ca761c4ef4bd2988")
|
|
|
++#define PUBLICKEY_B \
|
|
|
++ Constant_stringForHex("27c303cdc1f96e4b28d51c75130aff6cad52098f2d752615b7b6509ed6a89477")
|
|
|
+
|
|
|
+ #define USEROBJ "This represents a user"
|
|
|
+
|
|
|
+@@ -48,7 +50,11 @@ struct Context
|
|
|
+ struct EventBase* base;
|
|
|
+ };
|
|
|
+
|
|
|
+-static struct Context* init(uint8_t* privateKey, uint8_t* herPublicKey, uint8_t* password)
|
|
|
++static struct Context* init(uint8_t* privateKeyA,
|
|
|
++ uint8_t* publicKeyA,
|
|
|
++ uint8_t* password,
|
|
|
++ uint8_t* privateKeyB,
|
|
|
++ uint8_t* publicKeyB)
|
|
|
+ {
|
|
|
+ struct Allocator* alloc = MallocAllocator_new(1048576);
|
|
|
+ struct Context* ctx = Allocator_calloc(alloc, sizeof(struct Context), 1);
|
|
|
+@@ -57,14 +63,14 @@ static struct Context* init(uint8_t* privateKey, uint8_t* herPublicKey, uint8_t*
|
|
|
+ struct Random* rand = ctx->rand = Random_new(alloc, logger, NULL);
|
|
|
+ struct EventBase* base = ctx->base = EventBase_new(alloc);
|
|
|
+
|
|
|
+- ctx->ca1 = CryptoAuth_new(alloc, NULL, base, logger, rand);
|
|
|
+- ctx->sess1 = CryptoAuth_newSession(ctx->ca1, alloc, herPublicKey, NULL, false, "cif1");
|
|
|
++ ctx->ca1 = CryptoAuth_new(alloc, privateKeyA, base, logger, rand);
|
|
|
++ ctx->sess1 = CryptoAuth_newSession(ctx->ca1, alloc, publicKeyB, NULL, false, "cif1");
|
|
|
+
|
|
|
+- ctx->ca2 = CryptoAuth_new(alloc, privateKey, base, logger, rand);
|
|
|
++ ctx->ca2 = CryptoAuth_new(alloc, privateKeyB, base, logger, rand);
|
|
|
+ if (password) {
|
|
|
+ String* passStr = String_CONST(password);
|
|
|
+ CryptoAuth_setAuth(passStr, NULL, ctx->sess1);
|
|
|
+- CryptoAuth_addUser(passStr, NULL, String_new(USEROBJ, alloc), ctx->ca2);
|
|
|
++ CryptoAuth_addUser(passStr, String_new(USEROBJ, alloc), ctx->ca2);
|
|
|
+ }
|
|
|
+ ctx->sess2 = CryptoAuth_newSession(ctx->ca2, alloc, NULL, NULL, false, "cif2");
|
|
|
+
|
|
|
+@@ -73,7 +79,7 @@ static struct Context* init(uint8_t* privateKey, uint8_t* herPublicKey, uint8_t*
|
|
|
+
|
|
|
+ static struct Context* simpleInit()
|
|
|
+ {
|
|
|
+- return init(PRIVATEKEY, PUBLICKEY, NULL);
|
|
|
++ return init(PRIVATEKEY_A, PUBLICKEY_A, NULL, PRIVATEKEY_B, PUBLICKEY_B);
|
|
|
+ }
|
|
|
+
|
|
|
+ static struct Message* encryptMsg(struct Context* ctx,
|
|
|
+@@ -177,7 +183,7 @@ static void chatter()
|
|
|
+
|
|
|
+ static void auth()
|
|
|
+ {
|
|
|
+- struct Context* ctx = init(PRIVATEKEY, PUBLICKEY, "password");
|
|
|
++ struct Context* ctx = init(PRIVATEKEY_A, PUBLICKEY_A, "password", PRIVATEKEY_B, PUBLICKEY_B);
|
|
|
+ sendToIf2(ctx, "hello world");
|
|
|
+ sendToIf1(ctx, "hello cjdns");
|
|
|
+ sendToIf2(ctx, "hai");
|
|
|
+@@ -230,7 +236,7 @@ static void hellosCrossedOnTheWire()
|
|
|
+ struct Message* hello1 = encryptMsg(ctx, ctx->sess1, "hello1");
|
|
|
+
|
|
|
+ decryptMsg(ctx, hello2, ctx->sess1, "hello2");
|
|
|
+- decryptMsg(ctx, hello1, ctx->sess2, "hello1");
|
|
|
++ decryptMsg(ctx, hello1, ctx->sess2, NULL); //"hello1"); // The message is suppressed.
|
|
|
+
|
|
|
+ sendToIf2(ctx, "hello world");
|
|
|
+ sendToIf1(ctx, "hello cjdns");
|
|
|
+diff --git a/crypto/test/CryptoAuth_unit_test.c b/crypto/test/CryptoAuth_unit_test.c
|
|
|
+index 986576e..3bf49d0 100644
|
|
|
+--- a/crypto/test/CryptoAuth_unit_test.c
|
|
|
++++ b/crypto/test/CryptoAuth_unit_test.c
|
|
|
+@@ -197,12 +197,12 @@ static void testGetUsers()
|
|
|
+ users = CryptoAuth_getUsers(ca, allocator);
|
|
|
+ Assert_true(List_size(users) == 0);
|
|
|
+
|
|
|
+- CryptoAuth_addUser(String_CONST("pass1"), NULL, String_CONST("user1"), ca);
|
|
|
++ CryptoAuth_addUser(String_CONST("pass1"), String_CONST("user1"), ca);
|
|
|
+ users = CryptoAuth_getUsers(ca, allocator);
|
|
|
+ Assert_true(List_size(users) == 1);
|
|
|
+ Assert_true(String_equals(String_CONST("user1"), List_getString(users,0)));
|
|
|
+
|
|
|
+- CryptoAuth_addUser(String_CONST("pass2"), NULL, String_CONST("user2"), ca);
|
|
|
++ CryptoAuth_addUser(String_CONST("pass2"), String_CONST("user2"), ca);
|
|
|
+ users = CryptoAuth_getUsers(ca, allocator);
|
|
|
+ Assert_true(List_size(users) == 2);
|
|
|
+ Assert_true(String_equals(String_CONST("user2"),List_getString(users,0)));
|
|
|
+diff --git a/net/Benchmark.c b/net/Benchmark.c
|
|
|
+index a3b77eb..100d7d9 100644
|
|
|
+--- a/net/Benchmark.c
|
|
|
++++ b/net/Benchmark.c
|
|
|
+@@ -166,7 +166,7 @@ static void switching(struct Context* ctx)
|
|
|
+ InterfaceController_newIface(bob->ifController, String_CONST("bob"), alloc);
|
|
|
+ Iface_plumb(&sc->bobIf, &bobIci->addrIf);
|
|
|
+
|
|
|
+- CryptoAuth_addUser(String_CONST("abcdefg123"), NULL, String_CONST("TEST"), bob->ca);
|
|
|
++ CryptoAuth_addUser(String_CONST("abcdefg123"), String_CONST("TEST"), bob->ca);
|
|
|
+
|
|
|
+ // Client has pubKey and passwd for the server.
|
|
|
+ int ret = InterfaceController_bootstrapPeer(alice->ifController,
|
|
|
+diff --git a/net/InterfaceController.c b/net/InterfaceController.c
|
|
|
+index 39d78db..9a839ef 100644
|
|
|
+--- a/net/InterfaceController.c
|
|
|
++++ b/net/InterfaceController.c
|
|
|
+@@ -1018,7 +1018,7 @@ struct InterfaceController* InterfaceController_new(struct CryptoAuth* ca,
|
|
|
+ // Add the beaconing password.
|
|
|
+ Random_bytes(rand, out->beacon.password, Headers_Beacon_PASSWORD_LEN);
|
|
|
+ String strPass = { .bytes=(char*)out->beacon.password, .len=Headers_Beacon_PASSWORD_LEN };
|
|
|
+- int ret = CryptoAuth_addUser(&strPass, NULL, String_CONST("Local Peers"), ca);
|
|
|
++ int ret = CryptoAuth_addUser(&strPass, String_CONST("Local Peers"), ca);
|
|
|
+ if (ret) {
|
|
|
+ Log_warn(logger, "CryptoAuth_addUser() returned [%d]", ret);
|
|
|
+ }
|
|
|
+diff --git a/node_build/make.js b/node_build/make.js
|
|
|
+index f85725f..95336eb 100644
|
|
|
+--- a/node_build/make.js
|
|
|
++++ b/node_build/make.js
|
|
|
+@@ -44,7 +44,7 @@ Builder.configure({
|
|
|
+ crossCompiling: process.env['CROSS'] !== undefined,
|
|
|
+ gcc: GCC,
|
|
|
+ tempDir: '/tmp',
|
|
|
+- optimizeLevel: '-O3',
|
|
|
++ optimizeLevel: '-O0',
|
|
|
+ logLevel: process.env['Log_LEVEL'] || 'DEBUG'
|
|
|
+ }, function (builder, waitFor) {
|
|
|
+ builder.config.cflags.push(
|
|
|
+@@ -56,7 +56,7 @@ Builder.configure({
|
|
|
+ '-pedantic',
|
|
|
+ '-D', builder.config.systemName + '=1',
|
|
|
+ '-Wno-unused-parameter',
|
|
|
+- '-fomit-frame-pointer',
|
|
|
++// '-fomit-frame-pointer',
|
|
|
+
|
|
|
+ '-D', 'Log_' + builder.config.logLevel,
|
|
|
+
|
|
|
+diff --git a/test/TestFramework.c b/test/TestFramework.c
|
|
|
+index 3c780ef..e799651 100644
|
|
|
+--- a/test/TestFramework.c
|
|
|
++++ b/test/TestFramework.c
|
|
|
+@@ -185,7 +185,7 @@ void TestFramework_linkNodes(struct TestFramework* client,
|
|
|
+ Assert_true(!ret);
|
|
|
+ } else {
|
|
|
+ // Except that it has an authorizedPassword added.
|
|
|
+- CryptoAuth_addUser(String_CONST("abcdefg123"), NULL, String_CONST("TEST"), server->nc->ca);
|
|
|
++ CryptoAuth_addUser(String_CONST("abcdefg123"), String_CONST("TEST"), server->nc->ca);
|
|
|
+
|
|
|
+ // Client has pubKey and passwd for the server.
|
|
|
+ InterfaceController_bootstrapPeer(client->nc->ifController,
|
|
|
+diff --git a/tools/lib/publicToIp6.js b/tools/lib/publicToIp6.js
|
|
|
+index 5cdaac9..e7a2fb3 100644
|
|
|
+--- a/tools/lib/publicToIp6.js
|
|
|
++++ b/tools/lib/publicToIp6.js
|
|
|
+@@ -62,6 +62,7 @@ var Base32_decode = function (input) {
|
|
|
+ var convert = module.exports.convert = function (pubKey) {
|
|
|
+ if (pubKey.substring(pubKey.length-2) !== ".k") { throw new Error("key does not end with .k"); }
|
|
|
+ keyBytes = Base32_decode(pubKey.substring(0, pubKey.length-2));
|
|
|
++ //console.log(keyBytes.toString('hex'));
|
|
|
+ var hashOneBuff = new Buffer(Crypto.createHash('sha512').update(keyBytes).digest('hex'), 'hex');
|
|
|
+ var hashTwo = Crypto.createHash('sha512').update(hashOneBuff).digest('hex');
|
|
|
+ var first16 = hashTwo.substring(0,32);
|
|
|
+@@ -72,4 +73,7 @@ var convert = module.exports.convert = function (pubKey) {
|
|
|
+ return out.join(':');
|
|
|
+ };
|
|
|
+
|
|
|
++if (!module.parent) {
|
|
|
++ console.log(convert(process.argv[process.argv.length - 1]));
|
|
|
++}
|
|
|
+ //console.log(convert('rjndc8rvg194ddf2j5v679cfjcpmsmhv8p022q3lvpym21cqwyh0.k'));
|
|
|
+diff --git a/util/Constant.h b/util/Constant.h
|
|
|
+index 7807764..d348b95 100644
|
|
|
+--- a/util/Constant.h
|
|
|
++++ b/util/Constant.h
|
|
|
+@@ -17,6 +17,8 @@
|
|
|
+
|
|
|
+ <?js file.Constant_JS = require("../util/Constant.js"); ?>
|
|
|
+
|
|
|
++#define Constant_stringForHex(hex) <?js return file.Constant_JS.stringForHex( hex ) ?>
|
|
|
++
|
|
|
+ #define Constant_base2(num) <?js return file.Constant_JS.base2( #num ) ?>
|
|
|
+
|
|
|
+ #define Constant_rand64() <?js return file.Constant_JS.rand64(); ?>
|
|
|
+diff --git a/util/Constant.js b/util/Constant.js
|
|
|
+index 2d03ac0..9d26982 100644
|
|
|
+--- a/util/Constant.js
|
|
|
++++ b/util/Constant.js
|
|
|
+@@ -90,6 +90,15 @@ var log2 = module.exports.log2 = function (val) {
|
|
|
+ throw new Error("not an even power of 2");
|
|
|
+ };
|
|
|
+
|
|
|
++var stringForHex = module.exports.stringForHex = function (hex) {
|
|
|
++ var out = [];
|
|
|
++ for (var i = 0; i < hex.length; i+=2) {
|
|
|
++ out.push(hex[i] + hex[i+1]);
|
|
|
++ }
|
|
|
++ if (out.length < 2) { throw new Error(); }
|
|
|
++ return '"\\x' + out.join('\\x') + '"';
|
|
|
++};
|
|
|
++
|
|
|
+ if (!module.parent) {
|
|
|
+ console.log("testing " + __filename);
|
|
|
+ testBase2();
|