winlin

fix #165, refine dh wrapper, ensure public key is 128bytes. 0.9.206.

@@ -208,6 +208,7 @@ Supported operating systems and hardware: @@ -208,6 +208,7 @@ Supported operating systems and hardware:
208 * 2013-10-17, Created.<br/> 208 * 2013-10-17, Created.<br/>
209 209
210 ## History 210 ## History
  211 +* v1.0, 2014-08-22, for [#165](https://github.com/winlinvip/simple-rtmp-server/issues/165), refine dh wrapper, ensure public key is 128bytes. 0.9.206.
211 * v1.0, 2014-08-19, for [#160](https://github.com/winlinvip/simple-rtmp-server/issues/160), support forward/edge to flussonic, disable debug_srs_upnode to make flussonic happy. 0.9.201. 212 * v1.0, 2014-08-19, for [#160](https://github.com/winlinvip/simple-rtmp-server/issues/160), support forward/edge to flussonic, disable debug_srs_upnode to make flussonic happy. 0.9.201.
212 * v1.0, 2014-08-17, for [#155](https://github.com/winlinvip/simple-rtmp-server/issues/155), refine for osx, with ssl/http, disable statistics. 0.9.198. 213 * v1.0, 2014-08-17, for [#155](https://github.com/winlinvip/simple-rtmp-server/issues/155), refine for osx, with ssl/http, disable statistics. 0.9.198.
213 * v1.0, 2014-08-06, fix [#148](https://github.com/winlinvip/simple-rtmp-server/issues/148), simplify the RTMP handshake key generation. 0.9.191. 214 * v1.0, 2014-08-06, fix [#148](https://github.com/winlinvip/simple-rtmp-server/issues/148), simplify the RTMP handshake key generation. 0.9.191.
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR "0" 32 #define VERSION_MAJOR "0"
33 #define VERSION_MINOR "9" 33 #define VERSION_MINOR "9"
34 -#define VERSION_REVISION "205" 34 +#define VERSION_REVISION "206"
35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION 35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "SRS" 37 #define RTMP_SIG_SRS_KEY "SRS"
@@ -145,88 +145,100 @@ namespace _srs_internal @@ -145,88 +145,100 @@ namespace _srs_internal
145 "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ 145 "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
146 "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \ 146 "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
147 "FFFFFFFFFFFFFFFF" 147 "FFFFFFFFFFFFFFFF"
148 - /**  
149 - * initialize DH, create the public/private key.  
150 - */  
151 - int __openssl_initialize_dh(DH* pdh, int32_t bits_count)  
152 - {  
153 - int ret = ERROR_SUCCESS;  
154 148
155 - //2. Create his internal p and g  
156 - if ((pdh->p = BN_new()) == NULL) {  
157 - ret = ERROR_OpenSslCreateP;  
158 - return ret;  
159 - }  
160 - if ((pdh->g = BN_new()) == NULL) {  
161 - ret = ERROR_OpenSslCreateG;  
162 - return ret;  
163 - } 149 + SrsDH::SrsDH()
  150 + {
  151 + pdh = NULL;
  152 + }
164 153
165 - //3. initialize p and g  
166 - if (BN_hex2bn(&pdh->p, RFC2409_PRIME_1024) == 0) {  
167 - ret = ERROR_OpenSslParseP1024;  
168 - return ret;  
169 - }  
170 - if (BN_set_word(pdh->g, 2) != 1) {  
171 - ret = ERROR_OpenSslSetG;  
172 - return ret; 154 + SrsDH::~SrsDH()
  155 + {
  156 + if (pdh != NULL) {
  157 + if (pdh->p != NULL) {
  158 + BN_free(pdh->p);
  159 + pdh->p = NULL;
  160 + }
  161 + if (pdh->g != NULL) {
  162 + BN_free(pdh->g);
  163 + pdh->g = NULL;
  164 + }
  165 + DH_free(pdh);
  166 + pdh = NULL;
173 } 167 }
  168 + }
174 169
175 - //4. Set the key length  
176 - pdh->length = bits_count;  
177 -  
178 - //5. Generate private and public key  
179 - if (DH_generate_key(pdh) != 1) {  
180 - ret = ERROR_OpenSslGenerateDHKeys;  
181 - return ret; 170 + int SrsDH::initialize(bool ensure_128bytes_public_key)
  171 + {
  172 + int ret = ERROR_SUCCESS;
  173 +
  174 + for (;;) {
  175 + if ((ret = do_initialize()) != ERROR_SUCCESS) {
  176 + return ret;
  177 + }
  178 +
  179 + if (ensure_128bytes_public_key) {
  180 + int32_t key_size = BN_num_bytes(pdh->pub_key);
  181 + if (key_size != 128) {
  182 + srs_warn("regenerate 128B key, current=%dB", key_size);
  183 + continue;
  184 + }
  185 + }
  186 +
  187 + break;
182 } 188 }
183 189
184 return ret; 190 return ret;
185 } 191 }
186 - /**  
187 - * create DH and copy the 128bytes public key.  
188 - */  
189 - int __openssl_copy_key(DH* pdh, char* public_key, int32_t size) 192 +
  193 + int SrsDH::copy_public_key(char* pkey, int32_t* ppkey_size)
190 { 194 {
191 int ret = ERROR_SUCCESS; 195 int ret = ERROR_SUCCESS;
192 196
193 - int32_t bits_count = 1024;  
194 -  
195 - // 2. generate the g, p, private/public key.  
196 - if ((ret = __openssl_initialize_dh(pdh, bits_count)) != ERROR_SUCCESS) {  
197 - return ret;  
198 - }  
199 -  
200 // copy public key to bytes. 197 // copy public key to bytes.
201 // sometimes, the key_size is 127, seems ok. 198 // sometimes, the key_size is 127, seems ok.
202 int32_t key_size = BN_num_bytes(pdh->pub_key); 199 int32_t key_size = BN_num_bytes(pdh->pub_key);
203 srs_assert(key_size > 0); 200 srs_assert(key_size > 0);
204 201
205 - if (BN_bn2bin(pdh->pub_key, (unsigned char*)public_key) != size) {  
206 - //("Unable to copy key"); return ret;  
207 - ret = ERROR_OpenSslCopyKey;  
208 - return ret; 202 + key_size = BN_bn2bin(pdh->pub_key, (unsigned char*)pkey);
  203 + srs_assert(key_size > 0);
  204 +
  205 + if (ppkey_size != NULL) {
  206 + // output the size of public key.
  207 + // @see https://github.com/winlinvip/simple-rtmp-server/issues/165
  208 + srs_assert(key_size <= *ppkey_size);
  209 + *ppkey_size = key_size;
209 } 210 }
210 211
211 return ret; 212 return ret;
212 } 213 }
213 - /**  
214 - * use exists DH to create and copy the 128bytes shared key.  
215 - * the peer public key used to generate the shared key.  
216 - */  
217 - int __openssl_copy_shared_key(DH* pdh, const char* peer_pub_key, int ppk_size, char* shared_key) 214 +
  215 + int SrsDH::copy_shared_key(const char* ppkey, int32_t ppkey_size, char* skey, int32_t* pskey_size)
218 { 216 {
219 int ret = ERROR_SUCCESS; 217 int ret = ERROR_SUCCESS;
220 218
221 BIGNUM* ppk = NULL; 219 BIGNUM* ppk = NULL;
222 - if ((ppk = BN_bin2bn((const unsigned char*)peer_pub_key, ppk_size, 0)) == NULL) { 220 + if ((ppk = BN_bin2bn((const unsigned char*)ppkey, ppkey_size, 0)) == NULL) {
223 ret = ERROR_OpenSslGetPeerPublicKey; 221 ret = ERROR_OpenSslGetPeerPublicKey;
224 return ret; 222 return ret;
225 } 223 }
226 224
227 - // if failed, donot return, do cleanup.  
228 - if (DH_compute_key((unsigned char*)shared_key, ppk, pdh) < 0) { 225 + // if failed, donot return, do cleanup, @see ./test/dhtest.c:168
  226 + int32_t key_size = DH_compute_key((unsigned char*)skey, ppk, pdh);
  227 +
  228 + if (key_size < ppkey_size) {
  229 + srs_warn("shared key size=%d, ppk_size=%d", key_size, ppkey_size);
  230 + }
  231 +
  232 + if (key_size < 0) {
229 ret = ERROR_OpenSslComputeSharedKey; 233 ret = ERROR_OpenSslComputeSharedKey;
  234 + } else {
  235 + if (pskey_size != NULL) {
  236 + if (key_size > *pskey_size) {
  237 + ret = ERROR_OpenSslComputeSharedKey;
  238 + } else {
  239 + *pskey_size = key_size;
  240 + }
  241 + }
230 } 242 }
231 243
232 if (ppk) { 244 if (ppk) {
@@ -235,60 +247,50 @@ namespace _srs_internal @@ -235,60 +247,50 @@ namespace _srs_internal
235 247
236 return ret; 248 return ret;
237 } 249 }
238 - /**  
239 - * create DH and copy the 128bytes public key,  
240 - * generate and copy the shared key.  
241 - */  
242 - int __openssl_compute_key(DH* pdh, const char* peer_pub_key, int ppk_size, char* public_key, char* shared_key) 250 +
  251 + int SrsDH::do_initialize()
243 { 252 {
244 int ret = ERROR_SUCCESS; 253 int ret = ERROR_SUCCESS;
245 254
246 - // create DH and copy the 128bytes public key  
247 - if ((ret = __openssl_copy_key(pdh, public_key, ppk_size)) != ERROR_SUCCESS) { 255 + int32_t bits_count = 1024;
  256 +
  257 + //1. Create the DH
  258 + if ((pdh = DH_new()) == NULL) {
  259 + ret = ERROR_OpenSslCreateDH;
248 return ret; 260 return ret;
249 } 261 }
250 -  
251 - // generate and copy the shared key  
252 - if ((ret = __openssl_copy_shared_key(pdh, peer_pub_key, ppk_size, shared_key)) != ERROR_SUCCESS) { 262 +
  263 + //2. Create his internal p and g
  264 + if ((pdh->p = BN_new()) == NULL) {
  265 + ret = ERROR_OpenSslCreateP;
253 return ret; 266 return ret;
254 } 267 }
255 -  
256 - return ret;  
257 - }  
258 - void __openssl_free(DH* pdh)  
259 - {  
260 - if (pdh != NULL) {  
261 - if (pdh->p != NULL) {  
262 - BN_free(pdh->p);  
263 - pdh->p = NULL;  
264 - }  
265 - if (pdh->g != NULL) {  
266 - BN_free(pdh->g);  
267 - pdh->g = NULL;  
268 - }  
269 - DH_free(pdh);  
270 - pdh = NULL; 268 + if ((pdh->g = BN_new()) == NULL) {
  269 + ret = ERROR_OpenSslCreateG;
  270 + return ret;
  271 + }
  272 +
  273 + //3. initialize p and g, @see ./test/ectest.c:260
  274 + if (!BN_hex2bn(&pdh->p, RFC2409_PRIME_1024)) {
  275 + ret = ERROR_OpenSslParseP1024;
  276 + return ret;
  277 + }
  278 + // @see ./test/bntest.c:1764
  279 + if (!BN_set_word(pdh->g, 2)) {
  280 + ret = ERROR_OpenSslSetG;
  281 + return ret;
271 } 282 }
272 - }  
273 - int openssl_generate_key(char* public_key, int32_t size)  
274 - {  
275 - int ret = ERROR_SUCCESS;  
276 283
277 - // Initialize  
278 - DH* pdh = NULL; 284 + // 4. Set the key length
  285 + pdh->length = bits_count;
279 286
280 - //1. Create the DH  
281 - if ((pdh = DH_new()) == NULL) {  
282 - ret = ERROR_OpenSslCreateDH; 287 + // 5. Generate private and public key
  288 + // @see ./test/dhtest.c:152
  289 + if (!DH_generate_key(pdh)) {
  290 + ret = ERROR_OpenSslGenerateDHKeys;
283 return ret; 291 return ret;
284 } 292 }
285 293
286 - // generate and copy key.  
287 - ret = __openssl_copy_key(pdh, public_key, size);  
288 -  
289 - // cleanup  
290 - __openssl_free(pdh);  
291 -  
292 return ret; 294 return ret;
293 } 295 }
294 296
@@ -933,13 +935,17 @@ namespace _srs_internal @@ -933,13 +935,17 @@ namespace _srs_internal
933 time = ::time(NULL); 935 time = ::time(NULL);
934 version = 0x01000504; // server s1 version 936 version = 0x01000504; // server s1 version
935 937
  938 + SrsDH dh;
  939 + if ((ret = dh.initialize(true)) != ERROR_SUCCESS) {
  940 + return ret;
  941 + }
936 if (schema == srs_schema0) { 942 if (schema == srs_schema0) {
937 srs_key_block_init(&block0.key); 943 srs_key_block_init(&block0.key);
938 srs_digest_block_init(&block1.digest); 944 srs_digest_block_init(&block1.digest);
939 945
940 // directly generate the public key. 946 // directly generate the public key.
941 // @see: https://github.com/winlinvip/simple-rtmp-server/issues/148 947 // @see: https://github.com/winlinvip/simple-rtmp-server/issues/148
942 - if ((ret = openssl_generate_key(block0.key.key, 128)) != ERROR_SUCCESS) { 948 + if ((ret = dh.copy_public_key((char*)block0.key.key, NULL)) != ERROR_SUCCESS) {
943 srs_error("calc s1 key failed. ret=%d", ret); 949 srs_error("calc s1 key failed. ret=%d", ret);
944 return ret; 950 return ret;
945 } 951 }
@@ -949,7 +955,7 @@ namespace _srs_internal @@ -949,7 +955,7 @@ namespace _srs_internal
949 955
950 // directly generate the public key. 956 // directly generate the public key.
951 // @see: https://github.com/winlinvip/simple-rtmp-server/issues/148 957 // @see: https://github.com/winlinvip/simple-rtmp-server/issues/148
952 - if ((ret = openssl_generate_key(block1.key.key, 128)) != ERROR_SUCCESS) { 958 + if ((ret = dh.copy_public_key((char*)block1.key.key, NULL)) != ERROR_SUCCESS) {
953 srs_error("calc s1 key failed. ret=%d", ret); 959 srs_error("calc s1 key failed. ret=%d", ret);
954 return ret; 960 return ret;
955 } 961 }
@@ -36,6 +36,9 @@ class SrsHandshakeBytes; @@ -36,6 +36,9 @@ class SrsHandshakeBytes;
36 36
37 #ifdef SRS_AUTO_SSL 37 #ifdef SRS_AUTO_SSL
38 38
  39 +// for openssl.
  40 +#include <openssl/hmac.h>
  41 +
39 namespace _srs_internal 42 namespace _srs_internal
40 { 43 {
41 /** 44 /**
@@ -117,6 +120,46 @@ namespace _srs_internal @@ -117,6 +120,46 @@ namespace _srs_internal
117 int openssl_HMACsha256(const void* key, int key_size, const void* data, int data_size, void* digest); 120 int openssl_HMACsha256(const void* key, int key_size, const void* data, int data_size, void* digest);
118 int openssl_generate_key(char* public_key, int32_t size); 121 int openssl_generate_key(char* public_key, int32_t size);
119 122
  123 + /**
  124 + * the DH wrapper.
  125 + */
  126 + class SrsDH
  127 + {
  128 + private:
  129 + DH* pdh;
  130 + public:
  131 + SrsDH();
  132 + virtual ~SrsDH();
  133 + public:
  134 + /**
  135 + * initialize dh, generate the public and private key.
  136 + * @param ensure_128bytes_public_key whether ensure public key is 128bytes,
  137 + * sometimes openssl generate 127bytes public key.
  138 + * default to false to donot ensure.
  139 + */
  140 + virtual int initialize(bool ensure_128bytes_public_key = false);
  141 + /**
  142 + * copy the public key.
  143 + * @param pkey the bytes to copy the public key.
  144 + * @param ppkey_size the max public key size, output the actual public key size.
  145 + * NULL to ignore.
  146 + * @remark, when ensure_128bytes_public_key, the size always 128.
  147 + */
  148 + virtual int copy_public_key(char* pkey, int32_t* ppkey_size);
  149 + /**
  150 + * generate and copy the shared key.
  151 + * generate the shared key with peer public key.
  152 + * @param ppkey peer public key.
  153 + * @param ppkey_size the size of ppkey.
  154 + * @param skey the computed shared key.
  155 + * @param pskey_size the max shared key size, output the actual shared key size.
  156 + * NULL to ignore.
  157 + */
  158 + virtual int copy_shared_key(const char* ppkey, int32_t ppkey_size, char* skey, int32_t* pskey_size);
  159 + private:
  160 + virtual int do_initialize();
  161 + };
  162 +
120 // calc the offset of key, 163 // calc the offset of key,
121 // the key->offset cannot be used as the offset of key. 164 // the key->offset cannot be used as the offset of key.
122 int srs_key_block_get_offset(key_block* key); 165 int srs_key_block_get_offset(key_block* key);
@@ -238,11 +238,24 @@ VOID TEST(ProtocolHandshakeTest, OpensslSha256) @@ -238,11 +238,24 @@ VOID TEST(ProtocolHandshakeTest, OpensslSha256)
238 // verify the dh key 238 // verify the dh key
239 VOID TEST(ProtocolHandshakeTest, DHKey) 239 VOID TEST(ProtocolHandshakeTest, DHKey)
240 { 240 {
  241 + _srs_internal::SrsDH dh;
  242 +
  243 + ASSERT_TRUE(ERROR_SUCCESS == dh.initialize(true));
  244 +
241 char pub_key1[128]; 245 char pub_key1[128];
242 - openssl_generate_key(pub_key1, 128); 246 + EXPECT_TRUE(ERROR_SUCCESS == dh.copy_public_key(pub_key1, NULL));
243 247
244 char pub_key2[128]; 248 char pub_key2[128];
245 - openssl_generate_key(pub_key2, 128); 249 + EXPECT_TRUE(ERROR_SUCCESS == dh.copy_public_key(pub_key2, NULL));
  250 +
  251 + EXPECT_TRUE(srs_bytes_equals(pub_key1, pub_key2, 128));
  252 +
  253 + // another dh
  254 + _srs_internal::SrsDH dh0;
  255 +
  256 + ASSERT_TRUE(ERROR_SUCCESS == dh0.initialize(true));
  257 +
  258 + EXPECT_TRUE(ERROR_SUCCESS == dh0.copy_public_key(pub_key2, NULL));
246 259
247 EXPECT_FALSE(srs_bytes_equals(pub_key1, pub_key2, 128)); 260 EXPECT_FALSE(srs_bytes_equals(pub_key1, pub_key2, 128));
248 } 261 }