mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	fix https://github.com/ossrs/srs/issues/3155 Build srt-1-fit fails with `standard attributes in middle of decl-specifiers` on GCC 12,Arch Linux. See https://github.com/Haivision/srt/releases/tag/v1.5.3
		
			
				
	
	
		
			229 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * SRT - Secure, Reliable, Transport
 | 
						|
 * Copyright (c) 2018 Haivision Systems Inc.
 | 
						|
 * 
 | 
						|
 * This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
						|
 * 
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
/*****************************************************************************
 | 
						|
written by
 | 
						|
   Haivision Systems Inc.
 | 
						|
 | 
						|
   2011-06-23 (jdube)
 | 
						|
		HaiCrypt initial implementation.
 | 
						|
   2014-03-11 (jdube)
 | 
						|
		Adaptation for SRT.
 | 
						|
*****************************************************************************/
 | 
						|
 | 
						|
#include <string.h>				/* memcpy */
 | 
						|
#include "hcrypt.h"
 | 
						|
 | 
						|
int hcryptCtx_Rx_Init(hcrypt_Session *crypto, hcrypt_Ctx *ctx, const HaiCrypt_Cfg *cfg)
 | 
						|
{
 | 
						|
	if (cfg) {
 | 
						|
		ctx->mode = (cfg->flags & HAICRYPT_CFG_F_GCM) ? HCRYPT_CTX_MODE_AESGCM : HCRYPT_CTX_MODE_AESCTR;
 | 
						|
	}
 | 
						|
	ctx->status = HCRYPT_CTX_S_INIT;
 | 
						|
 | 
						|
	ctx->msg_info = crypto->msg_info;
 | 
						|
 | 
						|
	if (cfg && hcryptCtx_SetSecret(crypto, ctx, &cfg->secret)) {
 | 
						|
		return(-1);
 | 
						|
	}
 | 
						|
	ctx->status = HCRYPT_CTX_S_SARDY;
 | 
						|
	return(0);
 | 
						|
}
 | 
						|
 | 
						|
int hcryptCtx_Rx_Rekey(hcrypt_Session *crypto, hcrypt_Ctx *ctx, unsigned char *sek, size_t sek_len)
 | 
						|
{
 | 
						|
	if (crypto->cryspr->ms_setkey(crypto->cryspr_cb, ctx, sek, sek_len)) {
 | 
						|
		HCRYPT_LOG(LOG_ERR, "cryspr setkey[%d](sek) failed\n", hcryptCtx_GetKeyIndex(ctx));
 | 
						|
		return(-1);
 | 
						|
	}
 | 
						|
	memcpy(ctx->sek, sek, sek_len);
 | 
						|
	ctx->sek_len = sek_len;
 | 
						|
 | 
						|
	HCRYPT_LOG(LOG_INFO, "updated context[%d]\n", hcryptCtx_GetKeyIndex(ctx));
 | 
						|
	HCRYPT_PRINTKEY(ctx->sek, ctx->sek_len, "sek");
 | 
						|
	ctx->status = HCRYPT_CTX_S_KEYED;
 | 
						|
	return(0);
 | 
						|
}
 | 
						|
 | 
						|
/* Parse Keying Material message */
 | 
						|
int hcryptCtx_Rx_ParseKM(hcrypt_Session *crypto, unsigned char *km_msg, size_t msg_len)
 | 
						|
{
 | 
						|
	size_t sek_len, salt_len;
 | 
						|
	unsigned char seks[HAICRYPT_KEY_MAX_SZ * 2];
 | 
						|
	int sek_cnt;
 | 
						|
	size_t kek_len = 0;
 | 
						|
	hcrypt_Ctx *ctx;
 | 
						|
	int do_pbkdf = 0;
 | 
						|
 | 
						|
	if (NULL == crypto) {
 | 
						|
		HCRYPT_LOG(LOG_ERR, "Rx_ParseKM: invalid params: crypto=%p\n", crypto);
 | 
						|
		return(-1);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Validate message content */
 | 
						|
	{
 | 
						|
		if (msg_len <= HCRYPT_MSG_KM_OFS_SALT) {
 | 
						|
			HCRYPT_LOG(LOG_WARNING, "KMmsg length too small (%zd)\n", msg_len);
 | 
						|
			return(-1);
 | 
						|
		}
 | 
						|
		salt_len = hcryptMsg_KM_GetSaltLen(km_msg);
 | 
						|
		sek_len = hcryptMsg_KM_GetSekLen(km_msg);
 | 
						|
 | 
						|
		if ((salt_len > HAICRYPT_SALT_SZ)
 | 
						|
		||	(sek_len > HAICRYPT_KEY_MAX_SZ)) {
 | 
						|
			HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg unsupported salt/key length\n");
 | 
						|
			return(-1);
 | 
						|
		}
 | 
						|
		if ((16 != sek_len)
 | 
						|
		&&  (24 != sek_len)
 | 
						|
		&&  (32 != sek_len)) {
 | 
						|
			HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg unsupported key length\n");
 | 
						|
			return(-1);
 | 
						|
		}
 | 
						|
		if (hcryptMsg_KM_HasBothSek(km_msg)) {
 | 
						|
			sek_cnt = 2;
 | 
						|
		} else {
 | 
						|
			sek_cnt = 1;
 | 
						|
		}
 | 
						|
		if (msg_len != (HCRYPT_MSG_KM_OFS_SALT + salt_len + (sek_cnt * sek_len) + HAICRYPT_WRAPKEY_SIGN_SZ)) {
 | 
						|
			HCRYPT_LOG(LOG_WARNING, "KMmsg length inconsistent (%zd,%zd,%zd)\n",
 | 
						|
				salt_len, sek_len, msg_len);
 | 
						|
			return(-1);
 | 
						|
		}
 | 
						|
 | 
						|
		/* Check options support  */
 | 
						|
		if (HCRYPT_CIPHER_AES_CTR != km_msg[HCRYPT_MSG_KM_OFS_CIPHER]
 | 
						|
			&& HCRYPT_CIPHER_AES_GCM != km_msg[HCRYPT_MSG_KM_OFS_CIPHER])
 | 
						|
		{
 | 
						|
			HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg unsupported cipher\n");
 | 
						|
			return(-1);
 | 
						|
		}
 | 
						|
 | 
						|
#if !CRYSPR_HAS_AESGCM
 | 
						|
		/* Only OpenSSL EVP crypto provider allows the use of GCM.Add this condition. Reject if GCM is not supported by the CRYSPR. */
 | 
						|
		if (HCRYPT_CIPHER_AES_GCM == km_msg[HCRYPT_MSG_KM_OFS_CIPHER])
 | 
						|
		{
 | 
						|
			HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg unsupported GCM cipher\n");
 | 
						|
			return(-1);
 | 
						|
		}
 | 
						|
#endif
 | 
						|
 | 
						|
		if (HCRYPT_CIPHER_AES_GCM == km_msg[HCRYPT_MSG_KM_OFS_CIPHER]
 | 
						|
			&& HCRYPT_AUTH_AES_GCM != km_msg[HCRYPT_MSG_KM_OFS_AUTH]) {
 | 
						|
			HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg GCM auth method was expected.\n");
 | 
						|
			return(-1);
 | 
						|
		}
 | 
						|
 | 
						|
		if (HCRYPT_CIPHER_AES_CTR == km_msg[HCRYPT_MSG_KM_OFS_CIPHER]
 | 
						|
			&& HCRYPT_AUTH_NONE != km_msg[HCRYPT_MSG_KM_OFS_AUTH]) {
 | 
						|
			HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg unsupported auth method\n");
 | 
						|
			return(-1);
 | 
						|
		}
 | 
						|
 | 
						|
		if (crypto->se != km_msg[HCRYPT_MSG_KM_OFS_SE]) {
 | 
						|
			HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg invalid SE\n");
 | 
						|
			return(-1);
 | 
						|
		}
 | 
						|
 | 
						|
		/* Check KEKI here and pick right key */
 | 
						|
		//>>todo
 | 
						|
		/*
 | 
						|
		 * We support no key exchange,
 | 
						|
		 * KEK is preshared or derived from a passphrase
 | 
						|
		 */
 | 
						|
	}
 | 
						|
 | 
						|
	/* Pick the context updated by this KMmsg */
 | 
						|
	if (hcryptMsg_KM_HasBothSek(km_msg) && (NULL != crypto->ctx)) {
 | 
						|
		ctx = crypto->ctx->alt; /* 2 SEK KM, start with inactive ctx */
 | 
						|
	} else {
 | 
						|
		ctx = &crypto->ctx_pair[hcryptMsg_KM_GetKeyIndex(km_msg)];
 | 
						|
	}
 | 
						|
	if (NULL == ctx) {
 | 
						|
		HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg invalid flags (no SEK)\n");
 | 
						|
		return(-1);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Check Salt and get if new */
 | 
						|
	if ((salt_len != ctx->salt_len)
 | 
						|
	||  (0 != memcmp(ctx->salt, &km_msg[HCRYPT_MSG_KM_OFS_SALT], salt_len))) {
 | 
						|
		/* Salt changed (or 1st KMmsg received) */
 | 
						|
		memcpy(ctx->salt, &km_msg[HCRYPT_MSG_KM_OFS_SALT], salt_len);
 | 
						|
		ctx->salt_len = salt_len;
 | 
						|
		do_pbkdf = 1; /* Impact on password derived kek */
 | 
						|
	}
 | 
						|
 | 
						|
	/* Check SEK length and get if new */
 | 
						|
	if (sek_len != ctx->sek_len) {
 | 
						|
		/* Key length changed or 1st KMmsg received */
 | 
						|
		ctx->sek_len = sek_len;
 | 
						|
		do_pbkdf = 1; /* Impact on password derived kek */
 | 
						|
	}
 | 
						|
 | 
						|
	/* Check cipher mode */
 | 
						|
	if (ctx->mode != km_msg[HCRYPT_MSG_KM_OFS_CIPHER])
 | 
						|
	{
 | 
						|
		HCRYPT_LOG(LOG_WARNING, "%s", "cipher mode mismatch\n");
 | 
						|
		return(-3);
 | 
						|
	}
 | 
						|
 | 
						|
	/* 
 | 
						|
	 * Regenerate KEK if it is password derived
 | 
						|
	 * and Salt or SEK length changed
 | 
						|
	 */
 | 
						|
	if (ctx->cfg.pwd_len && do_pbkdf) {
 | 
						|
		if (hcryptCtx_GenSecret(crypto, ctx)) {
 | 
						|
			return(-1);
 | 
						|
		}
 | 
						|
		ctx->status = HCRYPT_CTX_S_SARDY;
 | 
						|
		kek_len = sek_len;	/* KEK changed */
 | 
						|
	}
 | 
						|
 | 
						|
	/* Unwrap SEK(s) and set in context */
 | 
						|
	if (0 > crypto->cryspr->km_unwrap(crypto->cryspr_cb, seks,
 | 
						|
		&km_msg[HCRYPT_MSG_KM_OFS_SALT + salt_len], 
 | 
						|
		(unsigned int)((sek_cnt * sek_len) + HAICRYPT_WRAPKEY_SIGN_SZ))) {
 | 
						|
		HCRYPT_LOG(LOG_WARNING, "%s", "unwrap key failed\n");
 | 
						|
		return(-2); //Report unmatched shared secret
 | 
						|
	}
 | 
						|
	/*
 | 
						|
	 * First SEK in KMmsg is eSEK if both SEK present
 | 
						|
	 */
 | 
						|
	hcryptCtx_Rx_Rekey(crypto, ctx,
 | 
						|
		((2 == sek_cnt) && (ctx->flags & HCRYPT_MSG_F_oSEK)) ? &seks[sek_len] : &seks[0],
 | 
						|
		sek_len);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Refresh KMmsg cache to detect Keying Material changes
 | 
						|
	 */
 | 
						|
	ctx->KMmsg_len = msg_len;
 | 
						|
	memcpy(ctx->KMmsg_cache, km_msg, msg_len);
 | 
						|
 | 
						|
	/* update other (alternate) context if both SEK provided */
 | 
						|
	if (2 == sek_cnt) {
 | 
						|
		hcrypt_Ctx *alt = ctx->alt;
 | 
						|
 | 
						|
		memcpy(alt->salt, &km_msg[HCRYPT_MSG_KM_OFS_SALT], salt_len);
 | 
						|
		alt->salt_len = salt_len;
 | 
						|
 | 
						|
		if (kek_len) { /* New or changed KEK */
 | 
						|
			alt->status = HCRYPT_CTX_S_SARDY;
 | 
						|
		}
 | 
						|
 | 
						|
		hcryptCtx_Rx_Rekey(crypto, alt,
 | 
						|
			((2 == sek_cnt) && (alt->flags & HCRYPT_MSG_F_oSEK)) ? &seks[sek_len] : &seks[0],
 | 
						|
			sek_len);
 | 
						|
 | 
						|
		alt->KMmsg_len = msg_len;
 | 
						|
		memcpy(alt->KMmsg_cache, km_msg, msg_len);
 | 
						|
	}
 | 
						|
	return(0);
 | 
						|
}
 |