Пример #1
0
///Save a public key away to disk so it's completely usable...
WINEXPORT gboolean
cryptcurve25519_save_public_key(const char * key_id,	///< key id to save key under
				gpointer public_key,	///< pointer to public key data
				int keysize)		///< size of key
{
	CryptFramePublicKey*	pub;
	gpointer*	newpub;
	if (keysize != crypto_box_PUBLICKEYBYTES) {
		g_warning("%s.%d: Attempt to save a public key of %d bytes (instead of %d)"
		,	__FUNCTION__, __LINE__, keysize, crypto_box_PUBLICKEYBYTES);
		return FALSE;
	}
	if ((pub = cryptframe_public_key_by_id(key_id)) != NULL) {
		if (memcmp(public_key, pub->public_key, keysize) == 0) {
			return TRUE;
		}
		g_critical("%s.%d: Attempt to modify public key with id [%s]"
		,	__FUNCTION__, __LINE__, key_id);
		return FALSE;
	}
	newpub = malloc(keysize);
	memcpy(newpub, public_key, keysize);
	if (!_cryptcurve25519_save_a_key(key_id, PUBLICKEY, newpub)
	||	cryptframe_publickey_new(key_id, newpub) == NULL) {
		cryptcurve25519_purge_keypair(key_id);
		g_free(newpub); newpub = NULL;
		return FALSE;
	}
	if (DEBUG) {
		CryptFramePublicKey*	pub = cryptframe_public_key_by_id(key_id);
		g_return_val_if_fail(pub != NULL, FALSE);
		g_return_val_if_fail(memcmp(public_key, pub->public_key, keysize) == 0, FALSE);
	}
	return TRUE;
}
Пример #2
0
/// Associate the given key id with the given identity
/// Note that it is OK to associate multiple key ids with a given identity
/// but it is NOT OK to associate multiple identities with a given key id
/// Return TRUE if we could make the association (it's OK to make
/// the same valid association multiple times)
WINEXPORT gboolean
cryptframe_associate_identity(const char * identity,	///<[in] identity to associate key with
			      const char * key_id)	///<[in] key to associate with identity
{
	GHashTable*	key_id_map;
	const char*	found_identity;
	char*		key_id_duplicate;
	char*		identity_duplicate;
	INITMAPS;
	g_return_val_if_fail(key_id != NULL && identity != NULL, FALSE);
	if (cryptframe_public_key_by_id(key_id) == NULL) {
		g_critical("%s.%d: no public key associated with key id %s"
		,	__FUNCTION__, __LINE__, key_id);
		return FALSE;
	}
	found_identity = cryptframe_whois_key_id(key_id);
	if (found_identity) {
		if (strcmp(found_identity, identity) != 0) {
			g_critical("%s.%d: Key id %s cannot be associated with identity %s."
			" Already associated with identity %s", __FUNCTION__, __LINE__
			,	key_id, identity, found_identity);
			return FALSE;
		}
		return TRUE;
	}
	key_id_duplicate = g_strdup(key_id);
	identity_duplicate = g_strdup(identity);
	g_hash_table_insert(identity_map_by_key_id, key_id_duplicate, identity_duplicate);

	key_id_map = cryptframe_key_ids_for(identity);
	if (NULL == key_id_map) {
		key_id_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
		g_hash_table_insert(key_id_map_by_identity, identity_duplicate, key_id_map);
	}
	if (!g_hash_table_lookup((GHashTable*)key_id_map, key_id)) {
		g_hash_table_insert(key_id_map, key_id_duplicate, key_id_duplicate);
	}
	return TRUE;
}
Пример #3
0
/// Create a new public key - or return the existing public key with this id
WINEXPORT CryptFramePublicKey*
cryptframe_publickey_new (const char *key_id,	///< Key id of the given public key
			  gpointer public_key)	///< MALLOCed public key
{
	AssimObj*		aself;
	CryptFramePublicKey*	self;
	INITMAPS;
	g_return_val_if_fail(key_id != NULL && public_key != NULL, NULL);
	self = cryptframe_public_key_by_id(key_id);
	if (self) {
		return self;
	}
	aself = assimobj_new(sizeof(CryptFramePublicKey));
	aself->_finalize = _cryptframe_publickey_finalize;
	self = NEWSUBCLASS(CryptFramePublicKey, aself);
	self->key_id = g_strdup(key_id);
	self->key_size = crypto_box_PUBLICKEYBYTES;
	self->frame_type = FRAMETYPE_PUBKEYCURVE25519;
	self->public_key = public_key;
	g_hash_table_insert(public_key_map, self->key_id, self);
	DEBUGCKSUM3(self->key_id, public_key);
	return self;
}
Пример #4
0
/// Save a curve25519 key to a file.
FSTATIC gboolean
_cryptcurve25519_save_a_key(const char * key_id,///<[in] key_id to save
			 enum keytype ktype,	///<[in] type of key being saved
			 gconstpointer key)	///<[in] pointer to key
{
	ssize_t		keysize;
	guint32		createmode;
	int		fd;
	int		rc;
	char*		filename;

	if (!_is_legal_curve25519_key_id(key_id)) {
		g_warning("%s.%d: Key id %s is illegal", __FUNCTION__, __LINE__, key_id);
		return FALSE;
	}
	filename = curve25519_key_id_to_filename(key_id, ktype);

	if (PUBLICKEY == ktype) {
		keysize = crypto_box_PUBLICKEYBYTES;
		createmode = 0644;
	}else if (PRIVATEKEY == ktype) {
		keysize = crypto_box_SECRETKEYBYTES;
		createmode = 0600;
	}else{
		g_error("%s.%d: Key type %d is illegal", __FUNCTION__, __LINE__, ktype);
		g_return_val_if_reached(FALSE);
	}
	// If it's a public key, it may exist but not be writable by us...
	if (PUBLICKEY == ktype && g_access(filename, R_OK) == 0) {
		// So, let's check and see if it's what we think it should be...
		if (_cache_curve25519_keypair(key_id)) {
			CryptFramePublicKey*	pub = cryptframe_public_key_by_id(key_id);
			if (pub && memcmp(pub->public_key, key, keysize) == 0) {
				FREE(filename); filename = NULL;
				return TRUE;
			}
		}
	}
	fd = open(filename, O_WRONLY|O_CREAT, createmode);
	if (fd < 0 && (ENOENT == errno)) {
		char*		dirname = _cache_curve25519_key_id_to_dirname(key_id, ktype);
		_cryptcurve25519_make_cryptdir(dirname);
		FREE(dirname);
		fd = open(filename, O_WRONLY|O_CREAT, createmode);
	}
	if (fd < 0) {
		g_warning("%s.%d: cannot create file %s [%s]", __FUNCTION__, __LINE__
		,	filename, g_strerror(errno));
		g_free(filename);
		return FALSE;
	}
	DEBUGMSG4("Saving key to file %s", filename);
	DEBUGCKSUM4("Saved key:", key, keysize);
	rc = write(fd, key, keysize);
	if (rc != keysize) {
		g_warning("%s.%d: cannot write file %s: rc=%d [%s]", __FUNCTION__, __LINE__
		,	filename, rc, g_strerror(errno));
		close(fd);
		g_unlink(filename);
		g_free(filename);
		return FALSE;
	}
	if (close(fd) < 0) {
		g_warning("%s.%d: Close of file %s failed.", __FUNCTION__, __LINE__, filename);
		g_unlink(filename);
		g_free(filename);
		return FALSE;
	}
	chmod(filename, createmode); // Ignore umask...
	DEBUGMSG1("%s.%d: file %s successfully created!", __FUNCTION__, __LINE__, filename);
	g_free(filename);
	return TRUE;
}
Пример #5
0
/// Given marshalled packet data corresponding to an CryptCurve25519 frame
/// return the corresponding Frame
/// In other words, un-marshall the data...
/// In our case, this means we decrypt it in-place into many other frames...
WINEXPORT Frame*
cryptcurve25519_tlvconstructor(gpointer tlvstart,	///<[in/out] Start of marshalled CStringFrame data
			  gconstpointer pktend,		///<[in] Pointer to first invalid byte past 'tlvstart'
		          gpointer* ignorednewpkt,	///<[ignored] replacement packet
		          gpointer* ignoredpktend)	///<[ignored] end of replacement packet
{
	guint8*			valptr = get_generic_tlv_nonconst_value(tlvstart, pktend);
	guint8*			nonce;
	guint8*			cyphertext;
	const guint8*		tlvend8 = valptr + get_generic_tlv_len(tlvstart, pktend);
	guint8*			plaintext;
	CryptCurve25519*	ret;
	guint			namelen;
	gsize			cypherlength;
				// The first key name is in sender's key name
				// The second key name is in receiver's key name
	CryptFramePublicKey *	sender_public_key = NULL;
	CryptFramePrivateKey*	receiver_secret_key = NULL;
	const char*		sender_pubkey_id = NULL;
	const char*		rcvr_seckey_id = NULL;
	int			j;

	(void)ignorednewpkt; (void)ignoredpktend;
	valptr = get_generic_tlv_nonconst_value(tlvstart, pktend);
	for (j=0; j < 2; ++j) {
		char *	key_id;
		g_return_val_if_fail((gpointer)(valptr+2) <= pktend, NULL);
		namelen = tlv_get_guint8(valptr, pktend);
		valptr += 1;
		g_return_val_if_fail((gpointer)(valptr+namelen) <= pktend, NULL);
		key_id = (char *)valptr;
		g_return_val_if_fail (strnlen(key_id, namelen) == namelen -1, NULL);
		g_return_val_if_fail(_is_valid_curve25519_key_id(key_id
		, 	0 == j ? PUBLICKEY : PRIVATEKEY), NULL);
		if (0 == j) {
			sender_public_key = cryptframe_public_key_by_id(key_id);
			sender_pubkey_id = key_id;
		}else{
			receiver_secret_key = cryptframe_private_key_by_id(key_id);
			rcvr_seckey_id = key_id;
		}
		g_return_val_if_fail(key_id != NULL, NULL);
		valptr += namelen;
	}
	if (NULL == sender_public_key) {
		g_warning("%s.%d: No access to sender %s public key"
		,	__FUNCTION__, __LINE__, sender_pubkey_id);
		return NULL;
	}
	if (NULL == receiver_secret_key) {
		g_warning("%s.%d: No access to receiver %s private key"
		,	__FUNCTION__, __LINE__, rcvr_seckey_id);
		return NULL;
	}
	g_return_val_if_fail((gpointer)(valptr + (crypto_box_NONCEBYTES+crypto_box_MACBYTES)) <= pktend, NULL);
	nonce = valptr;
	cyphertext = nonce + crypto_box_NONCEBYTES;
	plaintext = cyphertext + crypto_box_MACBYTES;
	cypherlength = tlvend8 - cyphertext;
	DEBUGCKSUM4("nonce:", nonce, crypto_box_NONCEBYTES);
	DEBUGCKSUM4("sender   public key :", sender_public_key -> public_key,  crypto_box_PUBLICKEYBYTES);
	DEBUGCKSUM4("receiver private key:", receiver_secret_key->private_key, crypto_box_SECRETKEYBYTES);
	DEBUGMSG4("cypher offset versus tlvstart: %ld", (long)(cyphertext-(guint8*)tlvstart));
	DEBUGCKSUM4("cypher text:", cyphertext, cypherlength);
	if (crypto_box_open_easy(plaintext, cyphertext, cypherlength, nonce
	,	sender_public_key->public_key, receiver_secret_key->private_key) != 0) {
		g_warning("%s.%d: could not decrypt %d byte message encrypted with key pair [pub:%s, sec:%s]"
		,	__FUNCTION__, __LINE__, (int)cypherlength, sender_pubkey_id, rcvr_seckey_id);
		return NULL;
	}
	DEBUGCKSUM4("plain text:", plaintext, cypherlength-crypto_box_MACBYTES);
	// Note that our return value's size will determine where the beginning of the
	// decrypted data is (according to it's dataspace() member function)
	ret = cryptcurve25519_new(get_generic_tlv_type(tlvstart, pktend)
	,	(const char *)sender_pubkey_id
	,	rcvr_seckey_id, FALSE, 0);
	return (ret ? &(ret->baseclass.baseclass) : NULL);
}
Пример #6
0
/// Construct a new CryptCurve25519 object (frame).
CryptCurve25519*
cryptcurve25519_new(guint16 frame_type,	///<[in] TLV type of CryptCurve25519
	  const char * sender_key_id,	///<[in] name of sender's key
	  const char * receiver_key_id,	///<[in] name of receiver's key
	  gboolean     forsending,	///<[in] TRUE if this is for sending
	  gsize objsize)		///<[in] sizeof(this object) - or zero for default
{
	CryptFrame*		baseframe;
	CryptCurve25519*	ret;

	BINDDEBUG(CryptCurve25519);
	if (objsize < sizeof(CryptCurve25519)) {
		objsize = sizeof(CryptCurve25519);
	}
	if (NULL == sender_key_id) {
		sender_key_id = cryptframe_get_signing_key_id();
	}
	DEBUGMSG2("%s.%d:(%s, %s, %d)", __FUNCTION__, __LINE__, sender_key_id, receiver_key_id
	,	(int)objsize);
	g_return_val_if_fail(sender_key_id != NULL && receiver_key_id != NULL, NULL);
	if (!_is_valid_curve25519_key_id(receiver_key_id, PUBLICKEY)) {
		g_critical("%s.%d: public key name [%s] is invalid", __FUNCTION__, __LINE__, receiver_key_id);
		return NULL;
	}
	if (!_is_valid_curve25519_key_id(sender_key_id, PUBLICKEY)) {
		g_critical("%s.%d: public key name [%s] is invalid", __FUNCTION__, __LINE__, sender_key_id);
		return NULL;
	}
	baseframe = cryptframe_new(frame_type, sender_key_id, receiver_key_id, objsize);
	if (!_parentclass_finalize) {
		_parentclass_finalize = baseframe->baseclass.baseclass._finalize;
	}
	baseframe->baseclass.isvalid	= _cryptcurve25519_default_isvalid;
	baseframe->baseclass.updatedata	= _cryptcurve25519_updatedata;
	baseframe->baseclass.length	= TLVLEN(receiver_key_id, sender_key_id);
	baseframe->baseclass.baseclass._finalize = _cryptcurve25519_finalize;
	ret			= NEWSUBCLASS(CryptCurve25519, baseframe);
	ret->forsending		= forsending;
	ret->private_key	= cryptframe_private_key_by_id(forsending ? sender_key_id : receiver_key_id);
	ret->public_key		= cryptframe_public_key_by_id(forsending ? receiver_key_id : sender_key_id);
	if (ret->private_key && ret->public_key) {
		DEBUGCKSUM3("private_key:", ret->private_key->private_key, crypto_box_SECRETKEYBYTES);
		DEBUGCKSUM3("public_key:", ret->public_key->public_key, crypto_box_PUBLICKEYBYTES);
		DUMP3(__FUNCTION__, &ret->baseclass.baseclass.baseclass, " is return value");
		REF(ret->private_key);
		REF(ret->public_key);
	}else{
		if (!ret->private_key) {
			g_warning("%s.%d: Sender private key is NULL for key id %s", __FUNCTION__, __LINE__
			,	sender_key_id);
			abort();
		}
		if (!ret->public_key) {
			g_warning("%s.%d: Receiver public key is NULL for key id %s", __FUNCTION__, __LINE__
			,	receiver_key_id);
		}
		UNREF3(ret);
		return NULL;
	}
	return ret;
}
Пример #7
0
/// Validate and cache the requested curve25519 keypair (or just public if no private)
/// If it's already in memory (like a temporary key) we won't look for it on disk.
FSTATIC gboolean
_cache_curve25519_keypair(const char * key_id)	///< Key id of keypair to cache
{
	GStatBuf	statinfo;
	char *		filename;
	gpointer	public_key = NULL;
	gpointer	secret_key = NULL;
	gboolean	retval = TRUE;
	int		fd = -1;
	int		rc;
	
	/*
	 *	Coverity CID 1262413:
	 *	Coverity complains about this code with a Time of Check / Time of Use warning.
	 *	The file attributes we check in the stat calls below might have changed before
	 *	we read the key files.
	 *
	 *	Although this is true, it is unlikely because of the permissions of the
	 *	directories and files involved.
	 *
	 *	We only look at two attributes:
	 *	 - file size
	 *	 - file type
	 *	If the file size changes, we will detect that because we try and read one extra byte.
	 *	If the file type changes, we're screwed.  But that's really unlikely and
	 *	unlikely to have the code succeed when reading a socket, directory, fifo or device.
	 *	It might cause the program to hang (on read), but I think that's nearly inevitable
	 *	and not worth the trouble to fix.
	 *	If the file type changes, the open might hang too...
	 *	So, we're pretty paranoid, and I judge us to be at least as paranoid as necessary.
	 */
	
	if (cryptframe_public_key_by_id(key_id) != NULL) {
		return TRUE;
	}
	filename = curve25519_key_id_to_filename(key_id, PUBLICKEY);
	if (g_stat(filename, &statinfo) < 0) {
		g_warning("%s.%d: g_stat error [%s] NOT Caching key id %s [%s]"
		,	__FUNCTION__, __LINE__
		,	filename, key_id, g_strerror(errno));
		retval = FALSE;
		goto getout;
	}
	if (statinfo.st_size != crypto_box_PUBLICKEYBYTES || !S_ISREG(statinfo.st_mode)
	||	g_access(filename, R_OK) != 0) {
		retval = FALSE;
		g_warning("%s.%d: size/type/access error on %s NOT Caching key id %s"
		,	__FUNCTION__, __LINE__, filename, key_id);
		goto getout;
	}
	fd = open(filename, O_RDONLY);
	if (fd < 0) {
		retval = FALSE;
		g_warning("%s.%d: open error on %s NOT Caching key id %s", __FUNCTION__, __LINE__
		,	filename, key_id);
		goto getout;
	}
	public_key = g_malloc(crypto_box_PUBLICKEYBYTES+1);
	rc = read(fd, public_key, crypto_box_PUBLICKEYBYTES+1);
	if (rc != crypto_box_PUBLICKEYBYTES) {
		g_warning("%s.%d: public key read on %s returned %d instead of %d [%s]"
		,	__FUNCTION__, __LINE__, filename
		,	rc, crypto_box_PUBLICKEYBYTES, g_strerror(errno));
		retval = FALSE;
		goto getout;
	}

	close(fd); fd = -1;
	DEBUGCKSUM4(filename, public_key, crypto_box_PUBLICKEYBYTES);

	g_free(filename);
	filename = curve25519_key_id_to_filename(key_id, PRIVATEKEY);
	if (g_stat(filename, &statinfo) >= 0) {
		if (statinfo.st_size != crypto_box_SECRETKEYBYTES || !S_ISREG(statinfo.st_mode)) {
			g_warning("%s.%d: secret key stat on [%s] returned %d instead of %d [%s]"
			,	__FUNCTION__, __LINE__, filename
			,	(int)statinfo.st_size, crypto_box_SECRETKEYBYTES, g_strerror(errno));
			goto getout;
		}
		if (g_access(filename, R_OK) != 0) {
			// Someone else's secret key... Not a problem...
			goto getout;
		}
		secret_key = g_malloc(crypto_box_SECRETKEYBYTES+1);
		fd = open(filename, O_RDONLY);
		if (fd < 0) {
			retval = FALSE;
			g_warning("%s.%d: open error on %s NOT Caching key id %s", __FUNCTION__, __LINE__
			,	filename, key_id);
			goto getout;
		}
		rc = read(fd, secret_key, crypto_box_SECRETKEYBYTES+1);
		if (rc != crypto_box_SECRETKEYBYTES) {
			g_warning("%s.%d: secret key read of %s returned %d instead of %d [%s]"
			,	__FUNCTION__, __LINE__, filename
			,	rc, crypto_box_SECRETKEYBYTES, g_strerror(errno));
			retval = FALSE;
			goto getout;
		}
		DEBUGCKSUM4(filename, secret_key, crypto_box_SECRETKEYBYTES);
		close(fd); fd = -1;
	}
getout:
	// Coverity: CID 1262410 - It doesn't like verifying non-NULL in this error leg
	// But it's a goto error leg, and in the future the code might change.
	// So I like it as is...
	if (filename != NULL) {
		g_free(filename);
		filename = NULL;
	}
	if (fd >= 0) {
		close(fd); fd = -1;
	}
	if (retval) {
		g_assert(public_key != NULL);
		(void)cryptframe_publickey_new(key_id, public_key);
		if (secret_key) {
			(void)cryptframe_privatekey_new(key_id, secret_key);
		}
	}else{
		if (public_key) {
			g_free(public_key);
			public_key = NULL;
		}
		if (secret_key) {
			g_free(secret_key);
			secret_key = NULL;
		}
	}
	return retval;
}