158 lines
5.0 KiB
C
Raw Normal View History

// Copyright 2019 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "natsp.h"
#include "mem.h"
#include "util.h"
#include "crypto.h"
#include "nkeys.h"
// PREFIX_BYTE_SEED is the version byte used for encoded NATS Seeds
#define PREFIX_BYTE_SEED ((char) (18 << 3)) // Base32-encodes to 'S...'
// PREFIX_BYTE_PRIVATE is the version byte used for encoded NATS Private keys
#define PREFIX_BYTE_PRIVATE ((char) (15 << 3)) // Base32-encodes to 'P...'
// PREFIX_BYTE_SERVER is the version byte used for encoded NATS Servers
#define PREFIX_BYTE_SERVER ((char) (13 << 3)) // Base32-encodes to 'N...'
// PREFIX_BYTE_CLUSTER is the version byte used for encoded NATS Clusters
#define PREFIX_BYTE_CLUSTER ((char) (2 << 3)) // Base32-encodes to 'C...'
// PREFIX_BYTE_ACCOUNT is the version byte used for encoded NATS Accounts
#define PREFIX_BYTE_ACCOUNT ((char) 0) // Base32-encodes to 'A...'
// PREFIX_BYTE_USER is the version byte used for encoded NATS Users
#define PREFIX_BYTE_USER ((char) (20 << 3)) // Base32-encodes to 'U...'
static uint16_t
_getUInt16LittleEndian(char *src)
{
uint16_t b0 = (uint16_t) (src[0] & 0xFF);
uint16_t b1 = (uint16_t) (src[1] & 0xFF);
return (b0 | b1<<8);
}
static bool
_isValidPublicPrefixByte(char b)
{
switch (b)
{
case PREFIX_BYTE_USER:
case PREFIX_BYTE_SERVER:
case PREFIX_BYTE_CLUSTER:
case PREFIX_BYTE_ACCOUNT:
return true;
default:
return false;
}
}
static natsStatus
_decodeSeed(const char *seed, char *raw, int rawMax)
{
natsStatus s = NATS_OK;
uint16_t crc = 0;
char b1 = 0;
char b2 = 0;
int rawLen = 0;
s = nats_Base32_DecodeString(seed, raw, rawMax, &rawLen);
if (s != NATS_OK)
return NATS_UPDATE_ERR_STACK(s);
if (rawLen < 4)
return nats_setError(NATS_ERR, "%s", NKEYS_INVALID_ENCODED_KEY);
// Read the crc that is stored as the two last bytes
crc = _getUInt16LittleEndian((char*)(raw + rawLen - 2));
// ensure checksum is valid
if (!nats_CRC16_Validate((unsigned char*) raw, rawLen - 2, crc))
return nats_setError(NATS_ERR, "%s", NKEYS_INVALID_CHECKSUM);
// Need to do the reverse here to get back to internal representation.
b1 = raw[0] & 248; // 248 = 11111000
b2 = (raw[0]&7)<<5 | ((raw[1] & 248) >> 3); // 7 = 00000111
if (b1 != PREFIX_BYTE_SEED)
return nats_setError(NATS_ERR, "%s", NKEYS_INVALID_SEED);
if (!_isValidPublicPrefixByte(b2))
return nats_setError(NATS_ERR, "%s", NKEYS_INVALID_PREFIX);
return NATS_OK;
}
natsStatus
natsKeys_Sign(const char *encodedSeed, const unsigned char *input, int inputLen, unsigned char *signature)
{
natsStatus s = NATS_OK;
char *seed = NULL;
int seedLen = 0;
if ((input != NULL) && (inputLen == 0))
inputLen = (int) strlen((char*) input);
seedLen = (int)((strlen(encodedSeed) * 5) / 8);
seed = NATS_CALLOC(1, seedLen);
if (seed == NULL)
s = nats_setDefaultError(NATS_NO_MEMORY);
if (s == NATS_OK)
s = _decodeSeed(encodedSeed, seed, seedLen);
if (s == NATS_OK)
{
// The actual seed starts after the first 2 characters.
s = natsCrypto_Sign((const unsigned char*) (seed+2), input, inputLen, signature);
}
if (seed != NULL)
{
natsCrypto_Clear((void*) seed, seedLen);
NATS_FREE(seed);
}
return NATS_UPDATE_ERR_STACK(s);
}
natsStatus
nats_Sign(const char *encodedSeed,
const char *input,
unsigned char **signature,
int *signatureLength)
{
natsStatus s;
unsigned char sig[NATS_CRYPTO_SIGN_BYTES];
if (nats_IsStringEmpty(encodedSeed))
return nats_setError(NATS_INVALID_ARG, "%s", "seed cannot be empty");
if (nats_IsStringEmpty(input))
return nats_setError(NATS_INVALID_ARG, "%s", "input cannot be empty");
if ((signature == NULL) || (signatureLength == NULL))
return nats_setError(NATS_INVALID_ARG, "%s", "signature and/or signatureLength cannot be NULL");
s = natsKeys_Sign(encodedSeed, (const unsigned char*) input, (int) strlen(input), sig);
if (s != NATS_OK)
return NATS_UPDATE_ERR_STACK(s);
*signature = (unsigned char*) NATS_MALLOC(NATS_CRYPTO_SIGN_BYTES);
if (*signature == NULL)
return nats_setDefaultError(NATS_NO_MEMORY);
memcpy(*signature, sig, NATS_CRYPTO_SIGN_BYTES);
*signatureLength = NATS_CRYPTO_SIGN_BYTES;
return NATS_OK;
}