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    2014-03-11 (jdube)
17         Adaptation for SRT.
18 *****************************************************************************/
19 
20 #include <string.h>			/* memset, memcpy */
21 #ifdef _WIN32
22     #include <winsock2.h>
23     #include <ws2tcpip.h>
24 #else
25     #include <arpa/inet.h>		/* htonl, ntohl */
26 #endif
27 #include "hcrypt.h"
28 
29 /*
30  *  HaiCrypt SRT (Secure Reliable Transport) Media Stream (MS) Msg Prefix:
31  *  This is UDT data header with Crypto Key Flags (KF) added.
32  *  Header is in 32bit host order words in the context of the functions of this handler.
33  *
34  *      0                   1                   2                   3
35  *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
36  *      +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
37  * 0x00 |0|               Packet Sequence Number (pki)                  |
38  *      +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
39  * 0x04 |FF |o|KF |             Message Number                          |
40  *      +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
41  * 0x08 |                         Time Stamp                            |
42  *      +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
43  * 0x0C |                   Destination Socket ID)                      |
44  *      +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
45  *      |                            Payload...                         |
46  */
47 
48 
49 /*
50  *  HaiCrypt Standalone Transport Keying Material (KM) Msg header kept in SRT
51  *  Message and cache maintained in network order
52  *
53  *      0                   1                   2                   3
54  *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
55  *      +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
56  * 0x00 |0|Vers |   PT  |             Sign              |     resv      |
57  *      +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
58  *      ...                                                             .
59  */
60 
61 #define HCRYPT_MSG_SRT_HDR_SZ		16
62 #define HCRYPT_MSG_SRT_PFX_SZ		16
63 
64 #define HCRYPT_MSG_SRT_OFS_PKI  	0
65 #define HCRYPT_MSG_SRT_OFS_MSGNO	4
66 #define HCRYPT_MSG_SRT_SHF_KFLGS	27   //shift
67 
68 static hcrypt_MsgInfo _hcMsg_SRT_MsgInfo;
69 
hcryptMsg_SRT_GetKeyFlags(unsigned char * msg)70 static unsigned hcryptMsg_SRT_GetKeyFlags(unsigned char *msg)
71 {
72 	uint32_t msgno;
73 	memcpy(&msgno, &msg[HCRYPT_MSG_SRT_OFS_MSGNO], sizeof(msgno)); //header is in host order
74 	return((unsigned)((msgno >> HCRYPT_MSG_SRT_SHF_KFLGS) & HCRYPT_MSG_F_xSEK));
75 }
76 
hcryptMsg_SRT_GetPki(unsigned char * msg,int nwkorder)77 static hcrypt_Pki hcryptMsg_SRT_GetPki(unsigned char *msg, int nwkorder)
78 {
79 	hcrypt_Pki pki;
80 	memcpy(&pki, &msg[HCRYPT_MSG_SRT_OFS_PKI], sizeof(pki)); //header is in host order
81 	return (nwkorder ? htonl(pki) : pki);
82 }
83 
hcryptMsg_SRT_SetPki(unsigned char * msg,hcrypt_Pki pki)84 static void hcryptMsg_SRT_SetPki(unsigned char *msg, hcrypt_Pki pki)
85 {
86 	memcpy(&msg[HCRYPT_MSG_SRT_OFS_PKI], &pki, sizeof(pki)); //header is in host order
87 }
88 
hcryptMsg_SRT_ResetCache(unsigned char * pfx_cache,unsigned pkt_type,unsigned kflgs)89 static void hcryptMsg_SRT_ResetCache(unsigned char *pfx_cache, unsigned pkt_type, unsigned kflgs)
90 {
91 	switch(pkt_type) {
92 	case HCRYPT_MSG_PT_MS: /* Media Stream */
93 	/* Nothing to do, header filled by protocol */
94 		break;
95 	case HCRYPT_MSG_PT_KM: /* Keying Material */
96 		pfx_cache[HCRYPT_MSG_KM_OFS_VERSION] = (unsigned char)((HCRYPT_MSG_VERSION << 4) | pkt_type); // version || PT
97 		pfx_cache[HCRYPT_MSG_KM_OFS_SIGN]    = (unsigned char)((HCRYPT_MSG_SIGN >> 8) & 0xFF); // Haivision PnP Mfr ID
98 		pfx_cache[HCRYPT_MSG_KM_OFS_SIGN+1]  = (unsigned char)(HCRYPT_MSG_SIGN & 0xFF);
99 		pfx_cache[HCRYPT_MSG_KM_OFS_KFLGS]    = (unsigned char)kflgs; //HCRYPT_MSG_F_xxx
100 		break;
101 	default:
102 		break;
103 	}
104 }
105 
hcryptMsg_SRT_IndexMsg(unsigned char * msg,unsigned char * pfx_cache)106 static void hcryptMsg_SRT_IndexMsg(unsigned char *msg, unsigned char *pfx_cache)
107 {
108 	(void)msg;
109 	(void)pfx_cache;
110 	return; //nothing to do, header and index maintained by SRT
111 }
112 
hcryptMsg_SRT_ParseMsg(unsigned char * msg)113 static int hcryptMsg_SRT_ParseMsg(unsigned char *msg)
114 {
115 	int rc;
116 
117 	if ((HCRYPT_MSG_VERSION == hcryptMsg_KM_GetVersion(msg))	/* Version 1 */
118 	&&  (HCRYPT_MSG_PT_KM   == hcryptMsg_KM_GetPktType(msg))   	/* Keying Material */
119 	&&  (HCRYPT_MSG_SIGN    == hcryptMsg_KM_GetSign(msg))) {	/* 'HAI' PnP Mfr ID */
120 		rc = HCRYPT_MSG_PT_KM;
121 	} else {
122 		//Assume it's data.
123 		//SRT does not call this for MS msg
124 		rc = HCRYPT_MSG_PT_MS;
125 	}
126 
127 	switch(rc) {
128 	case HCRYPT_MSG_PT_MS:
129 		if (hcryptMsg_HasNoSek(&_hcMsg_SRT_MsgInfo, msg)
130 		||  hcryptMsg_HasBothSek(&_hcMsg_SRT_MsgInfo, msg)) {
131 			HCRYPT_LOG(LOG_ERR, "invalid MS msg flgs: %02x\n",
132 				hcryptMsg_GetKeyIndex(&_hcMsg_SRT_MsgInfo, msg));
133 			return(-1);
134 		}
135 		break;
136 	case HCRYPT_MSG_PT_KM:
137 		if (HCRYPT_SE_TSSRT != hcryptMsg_KM_GetSE(msg)) { //Check Stream Encapsulation (SE)
138 			HCRYPT_LOG(LOG_ERR, "invalid KM msg SE: %d\n",
139 				hcryptMsg_KM_GetSE(msg));
140 			return(-1);
141 		}
142 		if (hcryptMsg_KM_HasNoSek(msg)) {
143 			HCRYPT_LOG(LOG_ERR, "invalid KM msg flgs: %02x\n",
144 				hcryptMsg_KM_GetKeyIndex(msg));
145 			return(-1);
146 		}
147 		break;
148 	default:
149 		HCRYPT_LOG(LOG_ERR, "invalid pkt type: %d\n",	rc);
150 		rc = 0; /* unknown packet type */
151 		break;
152 	}
153 	return(rc);	/* -1: error, 0: unknown: >0: PT */
154 }
155 
156 static hcrypt_MsgInfo _hcMsg_SRT_MsgInfo;
157 
hcryptMsg_SRT_MsgInfo(void)158 hcrypt_MsgInfo *hcryptMsg_SRT_MsgInfo(void)
159 {
160 	_hcMsg_SRT_MsgInfo.hdr_len      = HCRYPT_MSG_SRT_HDR_SZ;
161 	_hcMsg_SRT_MsgInfo.pfx_len      = HCRYPT_MSG_SRT_PFX_SZ;
162 	_hcMsg_SRT_MsgInfo.getKeyFlags  = hcryptMsg_SRT_GetKeyFlags;
163 	_hcMsg_SRT_MsgInfo.getPki       = hcryptMsg_SRT_GetPki;
164 	_hcMsg_SRT_MsgInfo.setPki       = hcryptMsg_SRT_SetPki;
165 	_hcMsg_SRT_MsgInfo.resetCache   = hcryptMsg_SRT_ResetCache;
166 	_hcMsg_SRT_MsgInfo.indexMsg     = hcryptMsg_SRT_IndexMsg;
167 	_hcMsg_SRT_MsgInfo.parseMsg     = hcryptMsg_SRT_ParseMsg;
168 
169 	return(&_hcMsg_SRT_MsgInfo);
170 }
171 
172