1 /*
2  * SRT - Secure, Reliable, Transport
3  * Copyright (c) 2018 Haivision Systems Inc.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  */
10 
11 
12 /*****************************************************************************
13 written by
14    Haivision Systems Inc.
15 
16    2011-06-23 (jdube)
17         HaiCrypt initial implementation.
18    2014-03-11 (jdube)
19         Adaptation for SRT.
20 *****************************************************************************/
21 
22 #include <string.h>				/* memcpy */
23 #include "hcrypt.h"
24 
hcryptCtx_Rx_Init(hcrypt_Session * crypto,hcrypt_Ctx * ctx,const HaiCrypt_Cfg * cfg)25 int hcryptCtx_Rx_Init(hcrypt_Session *crypto, hcrypt_Ctx *ctx, const HaiCrypt_Cfg *cfg)
26 {
27     ctx->mode = HCRYPT_CTX_MODE_AESCTR;
28     ctx->status = HCRYPT_CTX_S_INIT;
29 
30     ctx->msg_info = crypto->msg_info;
31 
32     if (cfg && hcryptCtx_SetSecret(crypto, ctx, &cfg->secret)) {
33         return(-1);
34     }
35     ctx->status = HCRYPT_CTX_S_SARDY;
36     return(0);
37 }
38 
hcryptCtx_Rx_Rekey(hcrypt_Session * crypto,hcrypt_Ctx * ctx,unsigned char * sek,size_t sek_len)39 int hcryptCtx_Rx_Rekey(hcrypt_Session *crypto, hcrypt_Ctx *ctx, unsigned char *sek, size_t sek_len)
40 {
41 	if (crypto->cryspr->ms_setkey(crypto->cryspr_cb, ctx, sek, sek_len)) {
42 		HCRYPT_LOG(LOG_ERR, "cryspr setkey[%d](sek) failed\n", hcryptCtx_GetKeyIndex(ctx));
43 		return(-1);
44 	}
45 	memcpy(ctx->sek, sek, sek_len);
46 	ctx->sek_len = sek_len;
47 
48 	HCRYPT_LOG(LOG_INFO, "updated context[%d]\n", hcryptCtx_GetKeyIndex(ctx));
49 	HCRYPT_PRINTKEY(ctx->sek, ctx->sek_len, "sek");
50 	ctx->status = HCRYPT_CTX_S_KEYED;
51 	return(0);
52 }
53 
54 /* Parse Keying Material message */
hcryptCtx_Rx_ParseKM(hcrypt_Session * crypto,unsigned char * km_msg,size_t msg_len)55 int hcryptCtx_Rx_ParseKM(hcrypt_Session *crypto, unsigned char *km_msg, size_t msg_len)
56 {
57 	size_t sek_len, salt_len;
58 	unsigned char seks[HAICRYPT_KEY_MAX_SZ * 2];
59 	int sek_cnt;
60 	size_t kek_len = 0;
61 	hcrypt_Ctx *ctx;
62 	int do_pbkdf = 0;
63 
64 	if (NULL == crypto) {
65 		HCRYPT_LOG(LOG_ERR, "Rx_ParseKM: invalid params: crypto=%p\n", crypto);
66 		return(-1);
67 	}
68 
69 	/* Validate message content */
70 	{
71 		if (msg_len <= HCRYPT_MSG_KM_OFS_SALT) {
72 			HCRYPT_LOG(LOG_WARNING, "KMmsg length too small (%zd)\n", msg_len);
73 			return(-1);
74 		}
75 		salt_len = hcryptMsg_KM_GetSaltLen(km_msg);
76 		sek_len = hcryptMsg_KM_GetSekLen(km_msg);
77 
78 		if ((salt_len > HAICRYPT_SALT_SZ)
79 		||	(sek_len > HAICRYPT_KEY_MAX_SZ)) {
80 			HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg unsupported salt/key length\n");
81 			return(-1);
82 		}
83 		if ((16 != sek_len)
84 		&&  (24 != sek_len)
85 		&&  (32 != sek_len)) {
86 			HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg unsupported key length\n");
87 			return(-1);
88 		}
89 		if (hcryptMsg_KM_HasBothSek(km_msg)) {
90 			sek_cnt = 2;
91 		} else {
92 			sek_cnt = 1;
93 		}
94 		if (msg_len != (HCRYPT_MSG_KM_OFS_SALT + salt_len + (sek_cnt * sek_len) + HAICRYPT_WRAPKEY_SIGN_SZ)) {
95 			HCRYPT_LOG(LOG_WARNING, "KMmsg length inconsistent (%zd,%zd,%zd)\n",
96 				salt_len, sek_len, msg_len);
97 			return(-1);
98 		}
99 
100 		/* Check options support  */
101 		if ((HCRYPT_CIPHER_AES_CTR != km_msg[HCRYPT_MSG_KM_OFS_CIPHER])
102 		||  (HCRYPT_AUTH_NONE != km_msg[HCRYPT_MSG_KM_OFS_AUTH])) {
103 			HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg unsupported option\n");
104 			return(-1);
105 		}
106 
107 		if (crypto->se != km_msg[HCRYPT_MSG_KM_OFS_SE]) {
108 			HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg invalid SE\n");
109 			return(-1);
110 		}
111 
112 		/* Check KEKI here and pick right key */
113 		//>>todo
114 		/*
115 		 * We support no key exchange,
116 		 * KEK is preshared or derived from a passphrase
117 		 */
118 	}
119 
120 	/* Pick the context updated by this KMmsg */
121 	if (hcryptMsg_KM_HasBothSek(km_msg) && (NULL != crypto->ctx)) {
122 		ctx = crypto->ctx->alt; /* 2 SEK KM, start with inactive ctx */
123 	} else {
124 		ctx = &crypto->ctx_pair[hcryptMsg_KM_GetKeyIndex(km_msg)];
125 	}
126 	if (NULL == ctx) {
127 		HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg invalid flags (no SEK)\n");
128 		return(-1);
129 	}
130 
131 	/* Check Salt and get if new */
132 	if ((salt_len != ctx->salt_len)
133 	||  (0 != memcmp(ctx->salt, &km_msg[HCRYPT_MSG_KM_OFS_SALT], salt_len))) {
134 		/* Salt changed (or 1st KMmsg received) */
135 		memcpy(ctx->salt, &km_msg[HCRYPT_MSG_KM_OFS_SALT], salt_len);
136 		ctx->salt_len = salt_len;
137 		do_pbkdf = 1; /* Impact on password derived kek */
138 	}
139 
140 	/* Check SEK length and get if new */
141 	if (sek_len != ctx->sek_len) {
142 		/* Key length changed or 1st KMmsg received */
143 		ctx->sek_len = sek_len;
144 		do_pbkdf = 1; /* Impact on password derived kek */
145 	}
146 
147 	/*
148 	 * Regenerate KEK if it is password derived
149 	 * and Salt or SEK length changed
150 	 */
151 	if (ctx->cfg.pwd_len && do_pbkdf) {
152 		if (hcryptCtx_GenSecret(crypto, ctx)) {
153 			return(-1);
154 		}
155 		ctx->status = HCRYPT_CTX_S_SARDY;
156 		kek_len = sek_len;	/* KEK changed */
157 	}
158 
159 	/* Unwrap SEK(s) and set in context */
160 	if (0 > crypto->cryspr->km_unwrap(crypto->cryspr_cb, seks,
161 		&km_msg[HCRYPT_MSG_KM_OFS_SALT + salt_len],
162 		(sek_cnt * sek_len) + HAICRYPT_WRAPKEY_SIGN_SZ)) {
163 		HCRYPT_LOG(LOG_WARNING, "%s", "unwrap key failed\n");
164 		return(-2); //Report unmatched shared secret
165 	}
166 	/*
167 	 * First SEK in KMmsg is eSEK if both SEK present
168 	 */
169 	hcryptCtx_Rx_Rekey(crypto, ctx,
170 		((2 == sek_cnt) && (ctx->flags & HCRYPT_MSG_F_oSEK)) ? &seks[sek_len] : &seks[0],
171 		sek_len);
172 
173 	/*
174 	 * Refresh KMmsg cache to detect Keying Material changes
175 	 */
176 	ctx->KMmsg_len = msg_len;
177 	memcpy(ctx->KMmsg_cache, km_msg, msg_len);
178 
179 	/* update other (alternate) context if both SEK provided */
180 	if (2 == sek_cnt) {
181 		hcrypt_Ctx *alt = ctx->alt;
182 
183 		memcpy(alt->salt, &km_msg[HCRYPT_MSG_KM_OFS_SALT], salt_len);
184 		alt->salt_len = salt_len;
185 
186 		if (kek_len) { /* New or changed KEK */
187 //			memcpy(&alt->aes_kek, &ctx->aes_kek, sizeof(alt->aes_kek));
188 			alt->status = HCRYPT_CTX_S_SARDY;
189 		}
190 
191 		hcryptCtx_Rx_Rekey(crypto, alt,
192 			((2 == sek_cnt) && (alt->flags & HCRYPT_MSG_F_oSEK)) ? &seks[sek_len] : &seks[0],
193 			sek_len);
194 
195 		alt->KMmsg_len = msg_len;
196 		memcpy(alt->KMmsg_cache, km_msg, msg_len);
197 	}
198 	return(0);
199 }
200