Update Files
This commit is contained in:
		
							
								
								
									
										412
									
								
								Kinc/Sources/kinc/libs/tls/openssl/lws-genaes.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										412
									
								
								Kinc/Sources/kinc/libs/tls/openssl/lws-genaes.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,412 @@ | ||||
|  /* | ||||
|  * libwebsockets - small server side websockets and web server implementation | ||||
|  * | ||||
|  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to | ||||
|  * deal in the Software without restriction, including without limitation the | ||||
|  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
|  * sell copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|  * IN THE SOFTWARE. | ||||
|  * | ||||
|  *  lws_genaes provides an AES abstraction api in lws that works the | ||||
|  *  same whether you are using openssl or mbedtls hash functions underneath. | ||||
|  */ | ||||
| #include "private-lib-core.h" | ||||
| #if defined(LWS_WITH_JOSE) | ||||
| #include "private-lib-jose.h" | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * Care: many openssl apis return 1 for success.  These are translated to the | ||||
|  * lws convention of 0 for success. | ||||
|  */ | ||||
|  | ||||
| int | ||||
| lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, | ||||
| 		  enum enum_aes_modes mode, struct lws_gencrypto_keyelem *el, | ||||
| 		  enum enum_aes_padding padding, void *engine) | ||||
| { | ||||
| 	int n = 0; | ||||
|  | ||||
| 	ctx->ctx = EVP_CIPHER_CTX_new(); | ||||
| 	if (!ctx->ctx) | ||||
| 		return -1; | ||||
|  | ||||
| 	ctx->mode = mode; | ||||
| 	ctx->k = el; | ||||
| 	ctx->engine = engine; | ||||
| 	ctx->init = 0; | ||||
| 	ctx->op = op; | ||||
| 	ctx->padding = padding; | ||||
|  | ||||
| 	switch (ctx->k->len) { | ||||
| 	case 128 / 8: | ||||
| 		switch (mode) { | ||||
| 		case LWS_GAESM_KW: | ||||
| #if defined(LWS_HAVE_EVP_aes_128_wrap) | ||||
| 			EVP_CIPHER_CTX_set_flags(ctx->ctx, | ||||
| 						EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); | ||||
| 			ctx->cipher = EVP_aes_128_wrap(); | ||||
| 			break; | ||||
| #else | ||||
| 			lwsl_err("%s: your OpenSSL lacks AES wrap apis, update it\n", | ||||
| 				 __func__); | ||||
| 			return -1; | ||||
| #endif | ||||
| 		case LWS_GAESM_CBC: | ||||
| 			ctx->cipher = EVP_aes_128_cbc(); | ||||
| 			break; | ||||
| #if defined(LWS_HAVE_EVP_aes_128_cfb128) | ||||
| 		case LWS_GAESM_CFB128: | ||||
| 			ctx->cipher = EVP_aes_128_cfb128(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_128_cfb8) | ||||
| 		case LWS_GAESM_CFB8: | ||||
| 			ctx->cipher = EVP_aes_128_cfb8(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_128_ctr) | ||||
| 		case LWS_GAESM_CTR: | ||||
| 			ctx->cipher = EVP_aes_128_ctr(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_128_ecb) | ||||
| 		case LWS_GAESM_ECB: | ||||
| 			ctx->cipher = EVP_aes_128_ecb(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_128_ofb) | ||||
| 		case LWS_GAESM_OFB: | ||||
| 			ctx->cipher = EVP_aes_128_ofb(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_128_xts) | ||||
| 		case LWS_GAESM_XTS: | ||||
| 			lwsl_err("%s: AES XTS requires double-length key\n", | ||||
| 				 __func__); | ||||
| 			break; | ||||
| #endif | ||||
| 		case LWS_GAESM_GCM: | ||||
| 			ctx->cipher = EVP_aes_128_gcm(); | ||||
| 			break; | ||||
| 		default: | ||||
| 			goto bail; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case 192 / 8: | ||||
| 		switch (mode) { | ||||
| 		case LWS_GAESM_KW: | ||||
| #if defined(LWS_HAVE_EVP_aes_128_wrap) | ||||
| 			EVP_CIPHER_CTX_set_flags(ctx->ctx, | ||||
| 						EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); | ||||
| 			ctx->cipher = EVP_aes_192_wrap(); | ||||
| 			break; | ||||
| #else | ||||
|                         lwsl_err("%s: your OpenSSL lacks AES wrap apis, update it\n", | ||||
|                                  __func__); | ||||
|                         return -1; | ||||
| #endif | ||||
| 		case LWS_GAESM_CBC: | ||||
| 			ctx->cipher = EVP_aes_192_cbc(); | ||||
| 			break; | ||||
| #if defined(LWS_HAVE_EVP_aes_192_cfb128) | ||||
| 		case LWS_GAESM_CFB128: | ||||
| 			ctx->cipher = EVP_aes_192_cfb128(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_192_cfb8) | ||||
| 		case LWS_GAESM_CFB8: | ||||
| 			ctx->cipher = EVP_aes_192_cfb8(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_128_ctr) | ||||
| 		case LWS_GAESM_CTR: | ||||
| 			ctx->cipher = EVP_aes_192_ctr(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_128_ecb) | ||||
| 		case LWS_GAESM_ECB: | ||||
| 			ctx->cipher = EVP_aes_192_ecb(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_128_ofb) | ||||
| 		case LWS_GAESM_OFB: | ||||
| 			ctx->cipher = EVP_aes_192_ofb(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_128_xts) | ||||
| 		case LWS_GAESM_XTS: | ||||
| 			lwsl_err("%s: AES XTS 192 invalid\n", __func__); | ||||
| 			goto bail; | ||||
| #endif | ||||
| 		case LWS_GAESM_GCM: | ||||
| 			ctx->cipher = EVP_aes_192_gcm(); | ||||
| 			break; | ||||
| 		default: | ||||
| 			goto bail; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case 256 / 8: | ||||
| 		switch (mode) { | ||||
| 		case LWS_GAESM_KW: | ||||
| #if defined(LWS_HAVE_EVP_aes_128_wrap) | ||||
| 			EVP_CIPHER_CTX_set_flags(ctx->ctx, | ||||
| 						EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); | ||||
| 			ctx->cipher = EVP_aes_256_wrap(); | ||||
| 			break; | ||||
| #else | ||||
|                         lwsl_err("%s: your OpenSSL lacks AES wrap apis, update it\n", | ||||
|                                  __func__); | ||||
|                         return -1; | ||||
| #endif | ||||
| 		case LWS_GAESM_CBC: | ||||
| 			ctx->cipher = EVP_aes_256_cbc(); | ||||
| 			break; | ||||
| #if defined(LWS_HAVE_EVP_aes_256_cfb128) | ||||
| 		case LWS_GAESM_CFB128: | ||||
| 			ctx->cipher = EVP_aes_256_cfb128(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_256_cfb8) | ||||
| 		case LWS_GAESM_CFB8: | ||||
| 			ctx->cipher = EVP_aes_256_cfb8(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_128_ctr) | ||||
| 		case LWS_GAESM_CTR: | ||||
| 			ctx->cipher = EVP_aes_256_ctr(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_128_ecb) | ||||
| 		case LWS_GAESM_ECB: | ||||
| 			ctx->cipher = EVP_aes_256_ecb(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_128_ofb) | ||||
| 		case LWS_GAESM_OFB: | ||||
| 			ctx->cipher = EVP_aes_256_ofb(); | ||||
| 			break; | ||||
| #endif | ||||
| #if defined(LWS_HAVE_EVP_aes_128_xts) | ||||
| 		case LWS_GAESM_XTS: | ||||
| 			ctx->cipher = EVP_aes_128_xts(); | ||||
| 			break; | ||||
| #endif | ||||
| 		case LWS_GAESM_GCM: | ||||
| 			ctx->cipher = EVP_aes_256_gcm(); | ||||
| 			break; | ||||
| 		default: | ||||
| 			goto bail; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case 512 / 8: | ||||
| 		switch (mode) { | ||||
| #if defined(LWS_HAVE_EVP_aes_128_xts) | ||||
| 		case LWS_GAESM_XTS: | ||||
| 			ctx->cipher = EVP_aes_256_xts(); | ||||
| #endif | ||||
| 			break; | ||||
| 		default: | ||||
| 			goto bail; | ||||
| 		} | ||||
| 	break; | ||||
|  | ||||
| 	default: | ||||
| 		lwsl_err("%s: unsupported AES size %d bits\n", __func__, | ||||
| 			 ctx->k->len * 8); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	switch (ctx->op) { | ||||
| 	case LWS_GAESO_ENC: | ||||
| 		n = EVP_EncryptInit_ex(ctx->ctx, ctx->cipher, ctx->engine, | ||||
| 				       NULL, NULL); | ||||
| 		EVP_CIPHER_CTX_set_padding(ctx->ctx, (int)padding); | ||||
| 		break; | ||||
| 	case LWS_GAESO_DEC: | ||||
| 		n = EVP_DecryptInit_ex(ctx->ctx, ctx->cipher, ctx->engine, | ||||
| 				       NULL, NULL); | ||||
| 		EVP_CIPHER_CTX_set_padding(ctx->ctx, (int)padding); | ||||
| 		break; | ||||
| 	} | ||||
| 	if (!n) { | ||||
| 		lwsl_err("%s: cipher init failed (cipher %p)\n", __func__, | ||||
| 			 ctx->cipher); | ||||
| 		lws_tls_err_describe_clear(); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| bail: | ||||
| 	EVP_CIPHER_CTX_free(ctx->ctx); | ||||
| 	ctx->ctx = NULL; | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen) | ||||
| { | ||||
| 	uint8_t buf[256]; | ||||
| 	int outl = sizeof(buf), n = 0; | ||||
|  | ||||
| 	if (!ctx->ctx) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (ctx->init) { | ||||
| 		switch (ctx->op) { | ||||
| 		case LWS_GAESO_ENC: | ||||
|  | ||||
| 			if (EVP_EncryptFinal_ex(ctx->ctx, buf, &outl) != 1) { | ||||
| 				lwsl_err("%s: enc final failed\n", __func__); | ||||
| 				n = -1; | ||||
| 			} | ||||
|  | ||||
| 			if (ctx->mode == LWS_GAESM_GCM) { | ||||
| 				if (EVP_CIPHER_CTX_ctrl(ctx->ctx, | ||||
| 						EVP_CTRL_GCM_GET_TAG, | ||||
| 						    ctx->taglen, tag) != 1) { | ||||
| 					lwsl_err("get tag ctrl failed\n"); | ||||
| 					//lws_tls_err_describe_clear(); | ||||
| 					n = 1; | ||||
| 				} | ||||
| 			} | ||||
| 			if (ctx->mode == LWS_GAESM_CBC) | ||||
| 				memcpy(tag, buf, (unsigned int)outl); | ||||
|  | ||||
| 			break; | ||||
|  | ||||
| 		case LWS_GAESO_DEC: | ||||
| 			if (EVP_DecryptFinal_ex(ctx->ctx, buf, &outl) != 1) { | ||||
| 				lwsl_err("%s: dec final failed\n", __func__); | ||||
| 				lws_tls_err_describe_clear(); | ||||
| 				n = -1; | ||||
| 			} | ||||
|  | ||||
| 			break; | ||||
| 		} | ||||
| 		if (outl) | ||||
| 			lwsl_debug("%s: final len %d\n", __func__, outl); | ||||
| 	} | ||||
|  | ||||
| 	ctx->k = NULL; | ||||
| 	EVP_CIPHER_CTX_free(ctx->ctx); | ||||
| 	ctx->ctx = NULL; | ||||
|  | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genaes_crypt(struct lws_genaes_ctx *ctx, | ||||
| 		 const uint8_t *in, size_t len, uint8_t *out, | ||||
| 		 uint8_t *iv_or_nonce_ctr_or_data_unit_16, | ||||
| 		 uint8_t *stream_block_16, size_t *nc_or_iv_off, int taglen) | ||||
| { | ||||
| 	int n = 0, outl, olen; | ||||
|  | ||||
| 	if (!ctx->init) { | ||||
|  | ||||
| 		EVP_CIPHER_CTX_set_key_length(ctx->ctx, (int)ctx->k->len); | ||||
|  | ||||
| 		if (ctx->mode == LWS_GAESM_GCM) { | ||||
| 			n = EVP_CIPHER_CTX_ctrl(ctx->ctx, EVP_CTRL_GCM_SET_IVLEN, | ||||
| 					   (int)*nc_or_iv_off, NULL); | ||||
| 			if (n != 1) { | ||||
| 				lwsl_err("%s: SET_IVLEN failed\n", __func__); | ||||
| 				return -1; | ||||
| 			} | ||||
| 			memcpy(ctx->tag, stream_block_16, (unsigned int)taglen); | ||||
| 			ctx->taglen = taglen; | ||||
| 		} | ||||
|  | ||||
| 		switch (ctx->op) { | ||||
| 		case LWS_GAESO_ENC: | ||||
| 			n = EVP_EncryptInit_ex(ctx->ctx, NULL, NULL, | ||||
| 					       ctx->k->buf, | ||||
| 					       iv_or_nonce_ctr_or_data_unit_16); | ||||
| 			break; | ||||
| 		case LWS_GAESO_DEC: | ||||
| 			if (ctx->mode == LWS_GAESM_GCM) | ||||
| 				EVP_CIPHER_CTX_ctrl(ctx->ctx, | ||||
| 						    EVP_CTRL_GCM_SET_TAG, | ||||
| 						    ctx->taglen, ctx->tag); | ||||
| 			n = EVP_DecryptInit_ex(ctx->ctx, NULL, NULL, | ||||
| 					       ctx->k->buf, | ||||
| 					       iv_or_nonce_ctr_or_data_unit_16); | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		if (!n) { | ||||
| 			lws_tls_err_describe_clear(); | ||||
| 			lwsl_err("%s: init failed (cipher %p)\n", | ||||
| 				 __func__, ctx->cipher); | ||||
|  | ||||
| 			return -1; | ||||
| 		} | ||||
| 		ctx->init = 1; | ||||
| 	} | ||||
|  | ||||
| 	if (ctx->mode == LWS_GAESM_GCM && !out) { | ||||
| 		/* AAD */ | ||||
|  | ||||
| 		if (!len) | ||||
| 			return 0; | ||||
|  | ||||
| 		switch (ctx->op) { | ||||
| 		case LWS_GAESO_ENC: | ||||
| 			n = EVP_EncryptUpdate(ctx->ctx, NULL, &olen, in, (int)len); | ||||
| 			break; | ||||
| 		case LWS_GAESO_DEC: | ||||
| 			n = EVP_DecryptUpdate(ctx->ctx, NULL, &olen, in, (int)len); | ||||
| 			break; | ||||
| 		default: | ||||
| 			return -1; | ||||
| 		} | ||||
| 		if (n != 1) { | ||||
| 			lwsl_err("%s: set AAD failed\n",  __func__); | ||||
| 			lws_tls_err_describe_clear(); | ||||
| 			lwsl_hexdump_err(in, len); | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	switch (ctx->op) { | ||||
| 	case LWS_GAESO_ENC: | ||||
| 		n = EVP_EncryptUpdate(ctx->ctx, out, &outl, in, (int)len); | ||||
| 		break; | ||||
| 	case LWS_GAESO_DEC: | ||||
| 		n = EVP_DecryptUpdate(ctx->ctx, out, &outl, in, (int)len); | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	// lwsl_notice("discarding outl %d\n", (int)outl); | ||||
|  | ||||
| 	if (!n) { | ||||
| 		lwsl_notice("%s: update failed\n", __func__); | ||||
| 		lws_tls_err_describe_clear(); | ||||
|  | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										89
									
								
								Kinc/Sources/kinc/libs/tls/openssl/lws-gencrypto.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								Kinc/Sources/kinc/libs/tls/openssl/lws-gencrypto.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,89 @@ | ||||
|  /* | ||||
|  * libwebsockets - small server side websockets and web server implementation | ||||
|  * | ||||
|  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to | ||||
|  * deal in the Software without restriction, including without limitation the | ||||
|  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
|  * sell copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|  * IN THE SOFTWARE. | ||||
|  * | ||||
|  *  lws-gencrypto openssl-specific common code | ||||
|  */ | ||||
|  | ||||
| #include "private-lib-core.h" | ||||
| #include "private-lib-tls-openssl.h" | ||||
|  | ||||
| /* | ||||
|  * Care: many openssl apis return 1 for success.  These are translated to the | ||||
|  * lws convention of 0 for success. | ||||
|  */ | ||||
|  | ||||
| int | ||||
| lws_gencrypto_openssl_hash_to_NID(enum lws_genhash_types hash_type) | ||||
| { | ||||
| 	int h = -1; | ||||
|  | ||||
| 	switch (hash_type) { | ||||
| 	case LWS_GENHASH_TYPE_UNKNOWN: | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_MD5: | ||||
| 		h = NID_md5; | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_SHA1: | ||||
| 		h = NID_sha1; | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_SHA256: | ||||
| 		h = NID_sha256; | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_SHA384: | ||||
| 		h = NID_sha384; | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_SHA512: | ||||
| 		h = NID_sha512; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return h; | ||||
| } | ||||
|  | ||||
| const EVP_MD * | ||||
| lws_gencrypto_openssl_hash_to_EVP_MD(enum lws_genhash_types hash_type) | ||||
| { | ||||
| 	const EVP_MD *h = NULL; | ||||
|  | ||||
| 	switch (hash_type) { | ||||
| 	case LWS_GENHASH_TYPE_UNKNOWN: | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_MD5: | ||||
| 		h = EVP_md5(); | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_SHA1: | ||||
| 		h = EVP_sha1(); | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_SHA256: | ||||
| 		h = EVP_sha256(); | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_SHA384: | ||||
| 		h = EVP_sha384(); | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_SHA512: | ||||
| 		h = EVP_sha512(); | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return h; | ||||
| } | ||||
							
								
								
									
										715
									
								
								Kinc/Sources/kinc/libs/tls/openssl/lws-genec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										715
									
								
								Kinc/Sources/kinc/libs/tls/openssl/lws-genec.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,715 @@ | ||||
|  /* | ||||
|  * libwebsockets - small server side websockets and web server implementation | ||||
|  * | ||||
|  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to | ||||
|  * deal in the Software without restriction, including without limitation the | ||||
|  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
|  * sell copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|  * IN THE SOFTWARE. | ||||
|  * | ||||
|  *  lws_genec provides an EC abstraction api in lws that works the | ||||
|  *  same whether you are using openssl or mbedtls crypto functions underneath. | ||||
|  */ | ||||
| #include "private-lib-core.h" | ||||
| #include "private-lib-tls-openssl.h" | ||||
|  | ||||
| #if !defined(OPENSSL_NO_EC) && defined(LWS_HAVE_EC_KEY_new_by_curve_name) && \ | ||||
|     (OPENSSL_VERSION_NUMBER >= 0x30000000l) && \ | ||||
|      !defined(LWS_SUPPRESS_DEPRECATED_API_WARNINGS) | ||||
| /* msvc doesn't have #warning... */ | ||||
| #error "You probably need LWS_SUPPRESS_DEPRECATED_API_WARNINGS" | ||||
| #endif | ||||
|  | ||||
| #if defined(USE_WOLFSSL) | ||||
| #include "openssl/ecdh.h" | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * Care: many openssl apis return 1 for success.  These are translated to the | ||||
|  * lws convention of 0 for success. | ||||
|  */ | ||||
|  | ||||
| #if defined(USE_WOLFSSL) | ||||
| EVP_PKEY * EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *p) | ||||
| { | ||||
| 	return p->pkey; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #if !defined(LWS_HAVE_ECDSA_SIG_set0) | ||||
| static void | ||||
| ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) | ||||
| { | ||||
|     if (pr != NULL) | ||||
|         *pr = sig->r; | ||||
|     if (ps != NULL) | ||||
|         *ps = sig->s; | ||||
| } | ||||
|  | ||||
| static int | ||||
| ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) | ||||
| { | ||||
| 	if (r == NULL || s == NULL) | ||||
| 		return 0; | ||||
| 	BN_clear_free(sig->r); | ||||
| 	BN_clear_free(sig->s); | ||||
| 	sig->r = r; | ||||
| 	sig->s = s; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| #endif | ||||
| #if !defined(LWS_HAVE_BN_bn2binpad) | ||||
| int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen) | ||||
| { | ||||
|     int i; | ||||
| #if !defined(USE_WOLFSSL) | ||||
|     BN_ULONG l; | ||||
| #endif | ||||
|  | ||||
| #if !defined(LIBRESSL_VERSION_NUMBER) && !defined(USE_WOLFSSL) | ||||
|     bn_check_top(a); | ||||
| #endif | ||||
|     i = BN_num_bytes(a); | ||||
|  | ||||
|     /* Add leading zeroes if necessary */ | ||||
|     if (tolen > i) { | ||||
|         memset(to, 0, (size_t)(tolen - i)); | ||||
|         to += tolen - i; | ||||
|     } | ||||
| #if defined(USE_WOLFSSL) | ||||
|     BN_bn2bin(a, to); | ||||
| #else | ||||
|     while (i--) { | ||||
|         l = a->d[i / BN_BYTES]; | ||||
|         *(to++) = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff; | ||||
|     } | ||||
| #endif | ||||
|     return tolen; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| const struct lws_ec_curves lws_ec_curves[4] = { | ||||
| 	/* | ||||
| 	 * These are the curves we are willing to use by default... | ||||
| 	 * | ||||
| 	 * The 3 recommended+ (P-256) and optional curves in RFC7518 7.6 | ||||
| 	 * | ||||
| 	 * Specific keys lengths from RFC8422 p20 | ||||
| 	 */ | ||||
| 	{ "P-256", NID_X9_62_prime256v1, 32 }, | ||||
| 	{ "P-384", NID_secp384r1,	 48 }, | ||||
| 	{ "P-521", NID_secp521r1,	 66 }, | ||||
|  | ||||
| 	{ NULL, 0, 0 } | ||||
| }; | ||||
|  | ||||
| static int | ||||
| lws_genec_eckey_import(int nid, EVP_PKEY *pkey, | ||||
| 		       const struct lws_gencrypto_keyelem *el) | ||||
| { | ||||
| 	EC_KEY *ec = EC_KEY_new_by_curve_name(nid); | ||||
| 	BIGNUM *bn_d, *bn_x, *bn_y; | ||||
| 	int n; | ||||
|  | ||||
| 	if (!ec) | ||||
| 		return -1; | ||||
|  | ||||
| 	/* | ||||
| 	 * EC_KEY contains | ||||
| 	 * | ||||
| 	 * EC_GROUP * 	group | ||||
| 	 * EC_POINT * 	pub_key | ||||
| 	 * BIGNUM * 	priv_key  (ie, d) | ||||
| 	 */ | ||||
|  | ||||
| 	bn_x = BN_bin2bn(el[LWS_GENCRYPTO_EC_KEYEL_X].buf, | ||||
| 			 (int)el[LWS_GENCRYPTO_EC_KEYEL_X].len, NULL); | ||||
| 	if (!bn_x) { | ||||
| 		lwsl_err("%s: BN_bin2bn (x) fail\n", __func__); | ||||
| 		goto bail; | ||||
| 	} | ||||
| 	bn_y = BN_bin2bn(el[LWS_GENCRYPTO_EC_KEYEL_Y].buf, | ||||
| 			(int)el[LWS_GENCRYPTO_EC_KEYEL_Y].len, NULL); | ||||
| 	if (!bn_y) { | ||||
| 		lwsl_err("%s: BN_bin2bn (y) fail\n", __func__); | ||||
| 		goto bail1; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * EC_KEY_set_public_key_affine_coordinates sets the public key for | ||||
| 	 * key based on its affine co-ordinates, i.e. it constructs an | ||||
| 	 * EC_POINT object based on the supplied x and y values and sets | ||||
| 	 * the public key to be this EC_POINT. It will also performs | ||||
| 	 * certain sanity checks on the key to confirm that it is valid. | ||||
| 	 */ | ||||
|  | ||||
| #if defined(USE_WOLFSSL) | ||||
| 	n = wolfSSL_EC_POINT_set_affine_coordinates_GFp(ec->group, | ||||
|                                                 ec->pub_key, | ||||
|                                                 bn_x, bn_y, | ||||
|                                                 NULL); | ||||
| #else | ||||
| 	n = EC_KEY_set_public_key_affine_coordinates(ec, bn_x, bn_y); | ||||
| #endif | ||||
| 	BN_free(bn_x); | ||||
| 	BN_free(bn_y); | ||||
| 	if (n != 1) { | ||||
| 		lwsl_err("%s: EC_KEY_set_public_key_affine_coordinates fail:\n", | ||||
| 			 __func__); | ||||
| 		lws_tls_err_describe_clear(); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	if (el[LWS_GENCRYPTO_EC_KEYEL_D].len) { | ||||
| 		bn_d = BN_bin2bn(el[LWS_GENCRYPTO_EC_KEYEL_D].buf, | ||||
| 				(int)el[LWS_GENCRYPTO_EC_KEYEL_D].len, NULL); | ||||
| 		if (!bn_d) { | ||||
| 			lwsl_err("%s: BN_bin2bn (d) fail\n", __func__); | ||||
| 			goto bail; | ||||
| 		} | ||||
|  | ||||
| 		n = EC_KEY_set_private_key(ec, bn_d); | ||||
| 		BN_clear_free(bn_d); | ||||
| 		if (n != 1) { | ||||
| 			lwsl_err("%s: EC_KEY_set_private_key fail\n", __func__); | ||||
| 			goto bail; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* explicitly confirm the key pieces are consistent */ | ||||
|  | ||||
| #if !defined(USE_WOLFSSL) | ||||
| 	if (EC_KEY_check_key(ec) != 1) { | ||||
| 		lwsl_err("%s: EC_KEY_set_private_key fail\n", __func__); | ||||
| 		goto bail; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	n = EVP_PKEY_assign_EC_KEY(pkey, ec); | ||||
| 	if (n != 1) { | ||||
| 		lwsl_err("%s: EVP_PKEY_set1_EC_KEY failed\n", __func__); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| bail1: | ||||
| 	BN_free(bn_x); | ||||
| bail: | ||||
| 	EC_KEY_free(ec); | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static int | ||||
| lws_genec_keypair_import(struct lws_genec_ctx *ctx, | ||||
| 			 const struct lws_ec_curves *curve_table, | ||||
| 			 EVP_PKEY_CTX **pctx, | ||||
| 			 const struct lws_gencrypto_keyelem *el) | ||||
| { | ||||
| 	EVP_PKEY *pkey = NULL; | ||||
| 	const struct lws_ec_curves *curve; | ||||
|  | ||||
| 	if (el[LWS_GENCRYPTO_EC_KEYEL_CRV].len < 4) | ||||
| 		return -2; | ||||
|  | ||||
| 	curve = lws_genec_curve(curve_table, | ||||
| 				(char *)el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf); | ||||
| 	if (!curve) | ||||
| 		return -3; | ||||
|  | ||||
| 	if ((el[LWS_GENCRYPTO_EC_KEYEL_D].len && | ||||
| 	     el[LWS_GENCRYPTO_EC_KEYEL_D].len != curve->key_bytes) || | ||||
| 	    el[LWS_GENCRYPTO_EC_KEYEL_X].len != curve->key_bytes || | ||||
| 	    el[LWS_GENCRYPTO_EC_KEYEL_Y].len != curve->key_bytes) | ||||
| 		return -4; | ||||
|  | ||||
| 	ctx->has_private = !!el[LWS_GENCRYPTO_EC_KEYEL_D].len; | ||||
|  | ||||
| 	pkey = EVP_PKEY_new(); | ||||
| 	if (!pkey) | ||||
| 		return -7; | ||||
|  | ||||
| 	if (lws_genec_eckey_import(curve->tls_lib_nid, pkey, el)) { | ||||
| 		lwsl_err("%s: lws_genec_eckey_import fail\n", __func__); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	*pctx = EVP_PKEY_CTX_new(pkey, NULL); | ||||
| 	EVP_PKEY_free(pkey); | ||||
| 	pkey = NULL; | ||||
|  | ||||
| 	if (!*pctx) | ||||
| 		goto bail; | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| bail: | ||||
| 	if (pkey) | ||||
| 		EVP_PKEY_free(pkey); | ||||
|  | ||||
| 	if (*pctx) { | ||||
| 		EVP_PKEY_CTX_free(*pctx); | ||||
| 		*pctx = NULL; | ||||
| 	} | ||||
|  | ||||
| 	return -9; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genecdh_create(struct lws_genec_ctx *ctx, struct lws_context *context, | ||||
| 		   const struct lws_ec_curves *curve_table) | ||||
| { | ||||
| 	ctx->context = context; | ||||
| 	ctx->ctx[0] = NULL; | ||||
| 	ctx->ctx[1] = NULL; | ||||
| 	ctx->curve_table = curve_table; | ||||
| 	ctx->genec_alg = LEGENEC_ECDH; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genecdsa_create(struct lws_genec_ctx *ctx, struct lws_context *context, | ||||
| 		    const struct lws_ec_curves *curve_table) | ||||
| { | ||||
| 	ctx->context = context; | ||||
| 	ctx->ctx[0] = NULL; | ||||
| 	ctx->ctx[1] = NULL; | ||||
| 	ctx->curve_table = curve_table; | ||||
| 	ctx->genec_alg = LEGENEC_ECDSA; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genecdh_set_key(struct lws_genec_ctx *ctx, struct lws_gencrypto_keyelem *el, | ||||
| 		    enum enum_lws_dh_side side) | ||||
| { | ||||
| 	if (ctx->genec_alg != LEGENEC_ECDH) | ||||
| 		return -1; | ||||
|  | ||||
| 	return lws_genec_keypair_import(ctx, ctx->curve_table, &ctx->ctx[side], el); | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genecdsa_set_key(struct lws_genec_ctx *ctx, | ||||
| 		     const struct lws_gencrypto_keyelem *el) | ||||
| { | ||||
| 	if (ctx->genec_alg != LEGENEC_ECDSA) | ||||
| 		return -1; | ||||
|  | ||||
| 	return lws_genec_keypair_import(ctx, ctx->curve_table, &ctx->ctx[0], el); | ||||
| } | ||||
|  | ||||
| static void | ||||
| lws_genec_keypair_destroy(EVP_PKEY_CTX **pctx) | ||||
| { | ||||
| 	if (!*pctx) | ||||
| 		return; | ||||
|  | ||||
| //	lwsl_err("%p\n", EVP_PKEY_get1_EC_KEY(EVP_PKEY_CTX_get0_pkey(*pctx))); | ||||
|  | ||||
| //	EC_KEY_free(EVP_PKEY_get1_EC_KEY(EVP_PKEY_CTX_get0_pkey(*pctx))); | ||||
|  | ||||
| 	EVP_PKEY_CTX_free(*pctx); | ||||
| 	*pctx = NULL; | ||||
| } | ||||
|  | ||||
| void | ||||
| lws_genec_destroy(struct lws_genec_ctx *ctx) | ||||
| { | ||||
| 	if (ctx->ctx[0]) | ||||
| 		lws_genec_keypair_destroy(&ctx->ctx[0]); | ||||
| 	if (ctx->ctx[1]) | ||||
| 		lws_genec_keypair_destroy(&ctx->ctx[1]); | ||||
| } | ||||
|  | ||||
| static int | ||||
| lws_genec_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, | ||||
| 		      const char *curve_name, struct lws_gencrypto_keyelem *el) | ||||
| { | ||||
| 	const struct lws_ec_curves *curve; | ||||
| 	const EC_POINT *pubkey; | ||||
| 	EVP_PKEY *pkey = NULL; | ||||
| 	int ret = -29, n, m; | ||||
| 	BIGNUM *bn[3]; | ||||
| 	EC_KEY *ec; | ||||
|  | ||||
| 	curve = lws_genec_curve(ctx->curve_table, curve_name); | ||||
| 	if (!curve) { | ||||
| 		lwsl_err("%s: curve '%s' not supported\n", | ||||
| 			 __func__, curve_name); | ||||
|  | ||||
| 		return -22; | ||||
| 	} | ||||
|  | ||||
| 	ec = EC_KEY_new_by_curve_name(curve->tls_lib_nid); | ||||
| 	if (!ec) { | ||||
| 		lwsl_err("%s: unknown nid %d\n", __func__, curve->tls_lib_nid); | ||||
| 		return -23; | ||||
| 	} | ||||
|  | ||||
| 	if (EC_KEY_generate_key(ec) != 1) { | ||||
| 		lwsl_err("%s: EC_KEY_generate_key failed\n", __func__); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	pkey = EVP_PKEY_new(); | ||||
| 	if (!pkey) | ||||
| 		goto bail; | ||||
|  | ||||
| 	if (EVP_PKEY_set1_EC_KEY(pkey, ec) != 1) { | ||||
| 		lwsl_err("%s: EVP_PKEY_assign_EC_KEY failed\n", __func__); | ||||
| 		goto bail1; | ||||
| 	} | ||||
|  | ||||
| 	ctx->ctx[side] = EVP_PKEY_CTX_new(pkey, NULL); | ||||
| 	if (!ctx->ctx[side]) { | ||||
| 		lwsl_err("%s: EVP_PKEY_CTX_new failed\n", __func__); | ||||
| 		goto bail1; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * we need to capture the individual element BIGNUMs into | ||||
| 	 * lws_gencrypto_keyelem, so they can be serialized, used in jwk etc | ||||
| 	 */ | ||||
|  | ||||
| 	pubkey = EC_KEY_get0_public_key(ec); | ||||
| 	if (!pubkey) { | ||||
| 		lwsl_err("%s: EC_KEY_get0_public_key failed\n", __func__); | ||||
| 		goto bail1; | ||||
| 	} | ||||
|  | ||||
| 	bn[0] = BN_new(); | ||||
| 	bn[1] = (BIGNUM *)EC_KEY_get0_private_key(ec); | ||||
| 	bn[2] = BN_new(); | ||||
|  | ||||
| #if defined(LWS_HAVE_EC_POINT_get_affine_coordinates) | ||||
| 	if (EC_POINT_get_affine_coordinates(EC_KEY_get0_group(ec), | ||||
| #else | ||||
| 	if (EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec), | ||||
| #endif | ||||
| 		        pubkey, bn[0], bn[2], NULL) != 1) { | ||||
| 		lwsl_err("%s: EC_POINT_get_affine_coordinates_GFp failed\n", | ||||
| 			 __func__); | ||||
| 		goto bail2; | ||||
| 	} | ||||
|  | ||||
| 	el[LWS_GENCRYPTO_EC_KEYEL_CRV].len = (uint32_t)strlen(curve_name) + 1; | ||||
| 	el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf = | ||||
| 			lws_malloc(el[LWS_GENCRYPTO_EC_KEYEL_CRV].len, "ec"); | ||||
| 	if (!el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf) { | ||||
| 		lwsl_err("%s: OOM\n", __func__); | ||||
| 		goto bail2; | ||||
| 	} | ||||
|  | ||||
| 	strcpy((char *)el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf, curve_name); | ||||
|  | ||||
| 	for (n = LWS_GENCRYPTO_EC_KEYEL_X; n < LWS_GENCRYPTO_EC_KEYEL_COUNT; | ||||
| 	     n++) { | ||||
| 		el[n].len = curve->key_bytes; | ||||
| 		el[n].buf = lws_malloc(curve->key_bytes, "ec"); | ||||
| 		if (!el[n].buf) | ||||
| 			goto bail2; | ||||
|  | ||||
| 		m = BN_bn2binpad(bn[n - 1], el[n].buf, (int32_t)el[n].len); | ||||
| 		if ((uint32_t)m != el[n].len) | ||||
| 			goto bail2; | ||||
| 	} | ||||
|  | ||||
| 	ctx->has_private = 1; | ||||
|  | ||||
| 	ret = 0; | ||||
|  | ||||
| bail2: | ||||
| 	BN_clear_free(bn[0]); | ||||
| 	BN_clear_free(bn[2]); | ||||
| bail1: | ||||
| 	EVP_PKEY_free(pkey); | ||||
| bail: | ||||
| 	EC_KEY_free(ec); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genecdh_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, | ||||
| 			const char *curve_name, | ||||
| 			struct lws_gencrypto_keyelem *el) | ||||
| { | ||||
| 	if (ctx->genec_alg != LEGENEC_ECDH) | ||||
| 		return -1; | ||||
|  | ||||
| 	return lws_genec_new_keypair(ctx, side, curve_name, el); | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name, | ||||
| 			 struct lws_gencrypto_keyelem *el) | ||||
| { | ||||
| 	if (ctx->genec_alg != LEGENEC_ECDSA) | ||||
| 		return -1; | ||||
|  | ||||
| 	return lws_genec_new_keypair(ctx, LDHS_OURS, curve_name, el); | ||||
| } | ||||
|  | ||||
| #if 0 | ||||
| int | ||||
| lws_genecdsa_hash_sign(struct lws_genec_ctx *ctx, const uint8_t *in, | ||||
| 		       enum lws_genhash_types hash_type, | ||||
| 		       uint8_t *sig, size_t sig_len) | ||||
| { | ||||
| 	const EVP_MD *md = lws_gencrypto_openssl_hash_to_EVP_MD(hash_type); | ||||
| 	EVP_MD_CTX *mdctx = NULL; | ||||
|  | ||||
| 	if (ctx->genec_alg != LEGENEC_ECDSA) | ||||
| 		return -1; | ||||
|  | ||||
| 	if (!md) | ||||
| 		return -1; | ||||
|  | ||||
| 	mdctx = EVP_MD_CTX_create(); | ||||
| 	if (!mdctx) | ||||
| 		goto bail; | ||||
|  | ||||
| 	if (EVP_DigestSignInit(mdctx, NULL, md, NULL, | ||||
| 			       EVP_PKEY_CTX_get0_pkey(ctx->ctx))) { | ||||
| 		lwsl_err("%s: EVP_DigestSignInit failed\n", __func__); | ||||
|  | ||||
| 		goto bail; | ||||
| 	} | ||||
| 	if (EVP_DigestSignUpdate(mdctx, in, EVP_MD_size(md))) { | ||||
| 		lwsl_err("%s: EVP_DigestSignUpdate failed\n", __func__); | ||||
|  | ||||
| 		goto bail; | ||||
| 	} | ||||
| 	if (EVP_DigestSignFinal(mdctx, sig, &sig_len)) { | ||||
| 		lwsl_err("%s: EVP_DigestSignFinal failed\n", __func__); | ||||
|  | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	EVP_MD_CTX_free(mdctx); | ||||
|  | ||||
| 	return (int)sig_len; | ||||
| bail: | ||||
| 	if (mdctx) | ||||
| 		EVP_MD_CTX_free(mdctx); | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| int | ||||
| lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in, | ||||
| 			   enum lws_genhash_types hash_type, int keybits, | ||||
| 			   uint8_t *sig, size_t sig_len) | ||||
| { | ||||
| 	int ret = -1, n, keybytes = lws_gencrypto_bits_to_bytes(keybits); | ||||
| 	size_t hs = lws_genhash_size(hash_type); | ||||
| 	const BIGNUM *r = NULL, *s = NULL; | ||||
| 	ECDSA_SIG *ecdsasig; | ||||
| 	EC_KEY *eckey; | ||||
|  | ||||
| 	if (ctx->genec_alg != LEGENEC_ECDSA) { | ||||
| 		lwsl_notice("%s: ctx alg %d\n", __func__, ctx->genec_alg); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (!ctx->has_private) | ||||
| 		return -1; | ||||
|  | ||||
| 	if ((int)sig_len != (int)(keybytes * 2)) { | ||||
| 		lwsl_notice("%s: sig buff %d < %d\n", __func__, | ||||
| 			    (int)sig_len, (int)(hs * 2)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	eckey = EVP_PKEY_get1_EC_KEY(EVP_PKEY_CTX_get0_pkey(ctx->ctx[0])); | ||||
|  | ||||
| 	/* | ||||
| 	 * The ECDSA P-256 SHA-256 digital signature is generated as follows: | ||||
| 	 * | ||||
| 	 * 1.  Generate a digital signature of the JWS Signing Input using ECDSA | ||||
| 	 *     P-256 SHA-256 with the desired private key.  The output will be | ||||
| 	 *     the pair (R, S), where R and S are 256-bit unsigned integers. | ||||
| 	 * | ||||
| 	 * 2.  Turn R and S into octet sequences in big-endian order, with each | ||||
| 	 *     array being be 32 octets long.  The octet sequence | ||||
| 	 *     representations MUST NOT be shortened to omit any leading zero | ||||
| 	 *     octets contained in the values. | ||||
| 	 * | ||||
| 	 * 3.  Concatenate the two octet sequences in the order R and then S. | ||||
| 	 *     (Note that many ECDSA implementations will directly produce this | ||||
| 	 *     concatenation as their output.) | ||||
| 	 * | ||||
| 	 * 4.  The resulting 64-octet sequence is the JWS Signature value. | ||||
| 	 */ | ||||
|  | ||||
| 	ecdsasig = ECDSA_do_sign(in, (int)hs, eckey); | ||||
| 	EC_KEY_free(eckey); | ||||
| 	if (!ecdsasig) { | ||||
| 		lwsl_notice("%s: ECDSA_do_sign fail\n", __func__); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	ECDSA_SIG_get0(ecdsasig, &r, &s); | ||||
|  | ||||
| 	/* | ||||
| 	 * in the 521-bit case, we have to pad the last byte as it only | ||||
| 	 * generates 65 bytes | ||||
| 	 */ | ||||
|  | ||||
| 	n = BN_bn2binpad(r, sig, keybytes); | ||||
| 	if (n != keybytes) { | ||||
| 		lwsl_notice("%s: bignum r fail %d %d\n", __func__, n, keybytes); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	n = BN_bn2binpad(s, sig + keybytes, keybytes); | ||||
| 	if (n != keybytes) { | ||||
| 		lwsl_notice("%s: bignum s fail %d %d\n", __func__, n, keybytes); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	ret = 0; | ||||
|  | ||||
| bail: | ||||
| 	if (ecdsasig) | ||||
| 		ECDSA_SIG_free(ecdsasig); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* in is the JWS Signing Input hash */ | ||||
|  | ||||
| int | ||||
| lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in, | ||||
| 				 enum lws_genhash_types hash_type, int keybits, | ||||
| 				 const uint8_t *sig, size_t sig_len) | ||||
| { | ||||
| 	int ret = -1, n, hlen = (int)lws_genhash_size(hash_type), | ||||
| 			keybytes = lws_gencrypto_bits_to_bytes(keybits); | ||||
| 	ECDSA_SIG *ecsig = ECDSA_SIG_new(); | ||||
| 	BIGNUM *r = NULL, *s = NULL; | ||||
| 	EC_KEY *eckey; | ||||
|  | ||||
| 	if (!ecsig) | ||||
| 		return -1; | ||||
|  | ||||
| 	if (ctx->genec_alg != LEGENEC_ECDSA) | ||||
| 		goto bail; | ||||
|  | ||||
| 	if ((int)sig_len != keybytes * 2) { | ||||
| 		lwsl_err("%s: sig buf size %d vs %d\n", __func__, | ||||
| 			 (int)sig_len, keybytes * 2); | ||||
| 		goto bail; | ||||
| 	} | ||||
| 	/* | ||||
| 	 * 1.  The JWS Signature value MUST be a 64-octet sequence.  If it is | ||||
| 	 *     not a 64-octet sequence, the validation has failed. | ||||
| 	 * | ||||
| 	 * 2.  Split the 64-octet sequence into two 32-octet sequences.  The | ||||
| 	 *     first octet sequence represents R and the second S.  The values R | ||||
| 	 *     and S are represented as octet sequences using the Integer-to- | ||||
| 	 *     OctetString Conversion defined in Section 2.3.7 of SEC1 [SEC1] | ||||
| 	 *     (in big-endian octet order). | ||||
| 	 * | ||||
| 	 * 3.  Submit the JWS Signing Input, R, S, and the public key (x, y) to | ||||
| 	 *     the ECDSA P-256 SHA-256 validator. | ||||
| 	 */ | ||||
|  | ||||
| 	r = BN_bin2bn(sig, keybytes, NULL); | ||||
| 	if (!r) { | ||||
| 		lwsl_err("%s: BN_bin2bn (r) fail\n", __func__); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	s = BN_bin2bn(sig + keybytes, keybytes, NULL); | ||||
| 	if (!s) { | ||||
| 		lwsl_err("%s: BN_bin2bn (s) fail\n", __func__); | ||||
| 		goto bail1; | ||||
| 	} | ||||
|  | ||||
| 	if (ECDSA_SIG_set0(ecsig, r, s) != 1) { | ||||
| 		lwsl_err("%s: ECDSA_SIG_set0 fail\n", __func__); | ||||
| 		goto bail1; | ||||
| 	} | ||||
|  | ||||
| 	eckey = EVP_PKEY_get1_EC_KEY(EVP_PKEY_CTX_get0_pkey(ctx->ctx[0])); | ||||
|  | ||||
| 	n = ECDSA_do_verify(in, hlen, ecsig, eckey); | ||||
| 	EC_KEY_free(eckey); | ||||
| 	if (n != 1) { | ||||
| 		lwsl_err("%s: ECDSA_do_verify fail, hlen %d\n", __func__, (int)hlen); | ||||
| 		lws_tls_err_describe_clear(); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	ret = 0; | ||||
| 	goto bail; | ||||
|  | ||||
| bail1: | ||||
| 	if (r) | ||||
| 		BN_free(r); | ||||
| 	if (s) | ||||
| 		BN_free(s); | ||||
|  | ||||
| bail: | ||||
| 	ECDSA_SIG_free(ecsig); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genecdh_compute_shared_secret(struct lws_genec_ctx *ctx, uint8_t *ss, | ||||
| 				  int *ss_len) | ||||
| { | ||||
| 	int len, ret = -1; | ||||
| 	EC_KEY *eckey[2]; | ||||
|  | ||||
| 	if (!ctx->ctx[LDHS_OURS] || !ctx->ctx[LDHS_THEIRS]) { | ||||
| 		lwsl_err("%s: both sides must be set up\n", __func__); | ||||
|  | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	eckey[LDHS_OURS] = EVP_PKEY_get1_EC_KEY( | ||||
| 				EVP_PKEY_CTX_get0_pkey(ctx->ctx[LDHS_OURS])); | ||||
| 	eckey[LDHS_THEIRS] = EVP_PKEY_get1_EC_KEY( | ||||
| 				EVP_PKEY_CTX_get0_pkey(ctx->ctx[LDHS_THEIRS])); | ||||
|  | ||||
| 	len = (EC_GROUP_get_degree(EC_KEY_get0_group(eckey[LDHS_OURS])) + 7) / 8; | ||||
| 	if (len <= *ss_len) { | ||||
| #if defined(USE_WOLFSSL) | ||||
| 		*ss_len = wolfSSL_ECDH_compute_key( | ||||
| #else | ||||
| 		*ss_len = ECDH_compute_key( | ||||
| #endif | ||||
| 				ss, (unsigned int)len, | ||||
| 				EC_KEY_get0_public_key(eckey[LDHS_THEIRS]), | ||||
| 				eckey[LDHS_OURS], NULL); | ||||
| 		ret = -(*ss_len < 0); | ||||
| 	} | ||||
|  | ||||
| 	EC_KEY_free(eckey[LDHS_OURS]); | ||||
| 	EC_KEY_free(eckey[LDHS_THEIRS]); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
							
								
								
									
										257
									
								
								Kinc/Sources/kinc/libs/tls/openssl/lws-genhash.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								Kinc/Sources/kinc/libs/tls/openssl/lws-genhash.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,257 @@ | ||||
|  /* | ||||
|  * libwebsockets - small server side websockets and web server implementation | ||||
|  * | ||||
|  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to | ||||
|  * deal in the Software without restriction, including without limitation the | ||||
|  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
|  * sell copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|  * IN THE SOFTWARE. | ||||
|  * | ||||
|  *  lws_genhash provides a hash / hmac abstraction api in lws that works the | ||||
|  *  same whether you are using openssl or mbedtls hash functions underneath. | ||||
|  */ | ||||
| #include <private-lib-core.h> | ||||
| #include <openssl/obj_mac.h> | ||||
| #include <openssl/opensslv.h> | ||||
| /* | ||||
|  * Care: many openssl apis return 1 for success.  These are translated to the | ||||
|  * lws convention of 0 for success. | ||||
|  */ | ||||
|  | ||||
| int | ||||
| lws_genhash_init(struct lws_genhash_ctx *ctx, enum lws_genhash_types type) | ||||
| { | ||||
| 	ctx->type = (uint8_t)type; | ||||
| 	ctx->mdctx = EVP_MD_CTX_create(); | ||||
| 	if (!ctx->mdctx) | ||||
| 		return 1; | ||||
|  | ||||
| 	switch (ctx->type) { | ||||
| 	case LWS_GENHASH_TYPE_MD5: | ||||
| 		ctx->evp_type = EVP_md5(); | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_SHA1: | ||||
| 		ctx->evp_type = EVP_sha1(); | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_SHA256: | ||||
| 		ctx->evp_type = EVP_sha256(); | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_SHA384: | ||||
| 		ctx->evp_type = EVP_sha384(); | ||||
| 		break; | ||||
| 	case LWS_GENHASH_TYPE_SHA512: | ||||
| 		ctx->evp_type = EVP_sha512(); | ||||
| 		break; | ||||
| 	default: | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (EVP_DigestInit_ex(ctx->mdctx, ctx->evp_type, NULL) != 1) { | ||||
| 		EVP_MD_CTX_destroy(ctx->mdctx); | ||||
|  | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len) | ||||
| { | ||||
| 	if (!len) | ||||
| 		return 0; | ||||
|  | ||||
| 	return EVP_DigestUpdate(ctx->mdctx, in, len) != 1; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result) | ||||
| { | ||||
| 	unsigned int len; | ||||
| 	int ret = 0; | ||||
|  | ||||
| 	if (!ctx->mdctx) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (result) | ||||
| 		ret = EVP_DigestFinal_ex(ctx->mdctx, result, &len) != 1; | ||||
|  | ||||
| 	(void)len; | ||||
|  | ||||
| 	EVP_MD_CTX_destroy(ctx->mdctx); | ||||
| 	ctx->mdctx = NULL; | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| #if defined(LWS_HAVE_EVP_PKEY_new_raw_private_key) | ||||
|  | ||||
| int | ||||
| lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type, | ||||
| 		 const uint8_t *key, size_t key_len) | ||||
| { | ||||
| 	ctx->ctx = EVP_MD_CTX_create(); | ||||
| 	if (!ctx->ctx) | ||||
| 		return -1; | ||||
|  | ||||
| 	ctx->evp_type = 0; | ||||
| 	ctx->type = (uint8_t)type; | ||||
|  | ||||
| 	switch (type) { | ||||
| 	case LWS_GENHMAC_TYPE_SHA256: | ||||
| 		ctx->evp_type = EVP_sha256(); | ||||
| 		break; | ||||
| 	case LWS_GENHMAC_TYPE_SHA384: | ||||
| 		ctx->evp_type = EVP_sha384(); | ||||
| 		break; | ||||
| 	case LWS_GENHMAC_TYPE_SHA512: | ||||
| 		ctx->evp_type = EVP_sha512(); | ||||
| 		break; | ||||
| 	default: | ||||
| 		lwsl_err("%s: unknown HMAC type %d\n", __func__, type); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	ctx->key = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, key, key_len); | ||||
| 	if (!ctx->key) | ||||
| 		goto bail; | ||||
|  | ||||
| 	if (EVP_DigestSignInit(ctx->ctx, NULL, ctx->evp_type, NULL, ctx->key) != 1) | ||||
| 		goto bail1; | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| bail1: | ||||
| 	EVP_PKEY_free(ctx->key); | ||||
| bail: | ||||
| 	EVP_MD_CTX_free(ctx->ctx); | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len) | ||||
| { | ||||
|  | ||||
| 	if (EVP_DigestSignUpdate(ctx->ctx, in, len) != 1) | ||||
| 		return -1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genhmac_destroy(struct lws_genhmac_ctx *ctx, void *result) | ||||
| { | ||||
| 	size_t size = (size_t)lws_genhmac_size(ctx->type); | ||||
| 	int n; | ||||
|  | ||||
| 	n = EVP_DigestSignFinal(ctx->ctx, result, &size); | ||||
| 	EVP_MD_CTX_free(ctx->ctx); | ||||
| 	EVP_PKEY_free(ctx->key); | ||||
|  | ||||
| 	if (n != 1) | ||||
| 		return -1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #else | ||||
|  | ||||
| int | ||||
| lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type, | ||||
| 		 const uint8_t *key, size_t key_len) | ||||
| { | ||||
| #if defined(LWS_HAVE_HMAC_CTX_new) | ||||
| 	ctx->ctx = HMAC_CTX_new(); | ||||
| 	if (!ctx->ctx) | ||||
| 		return -1; | ||||
| #else | ||||
| 	HMAC_CTX_init(&ctx->ctx); | ||||
| #endif | ||||
|  | ||||
| 	ctx->evp_type = 0; | ||||
| 	ctx->type = (uint8_t)type; | ||||
|  | ||||
| 	switch (type) { | ||||
| 	case LWS_GENHMAC_TYPE_SHA256: | ||||
| 		ctx->evp_type = EVP_sha256(); | ||||
| 		break; | ||||
| 	case LWS_GENHMAC_TYPE_SHA384: | ||||
| 		ctx->evp_type = EVP_sha384(); | ||||
| 		break; | ||||
| 	case LWS_GENHMAC_TYPE_SHA512: | ||||
| 		ctx->evp_type = EVP_sha512(); | ||||
| 		break; | ||||
| 	default: | ||||
| 		lwsl_err("%s: unknown HMAC type %d\n", __func__, type); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| #if defined(LWS_HAVE_HMAC_CTX_new) | ||||
|         if (HMAC_Init_ex(ctx->ctx, key, (int)key_len, ctx->evp_type, NULL) != 1) | ||||
| #else | ||||
|         if (HMAC_Init_ex(&ctx->ctx, key, (int)key_len, ctx->evp_type, NULL) != 1) | ||||
| #endif | ||||
|         	goto bail; | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| bail: | ||||
| #if defined(LWS_HAVE_HMAC_CTX_new) | ||||
| 	HMAC_CTX_free(ctx->ctx); | ||||
| #endif | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len) | ||||
| { | ||||
| #if defined(LWS_HAVE_HMAC_CTX_new) | ||||
| #if defined(LIBRESSL_VERSION_NUMBER) | ||||
| 	if (HMAC_Update(ctx->ctx, in, len) != 1) | ||||
| #else | ||||
| 	if (HMAC_Update(ctx->ctx, in, (int)len) != 1) | ||||
| #endif | ||||
| #else /* HMAC_CTX_new */ | ||||
| 	if (HMAC_Update(&ctx->ctx, in, len) != 1) | ||||
| #endif | ||||
| 		return -1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genhmac_destroy(struct lws_genhmac_ctx *ctx, void *result) | ||||
| { | ||||
| 	unsigned int size = (unsigned int)lws_genhmac_size(ctx->type); | ||||
| #if defined(LWS_HAVE_HMAC_CTX_new) | ||||
| 	int n = HMAC_Final(ctx->ctx, result, &size); | ||||
|  | ||||
| 	HMAC_CTX_free(ctx->ctx); | ||||
| #else | ||||
| 	int n = HMAC_Final(&ctx->ctx, result, &size); | ||||
| #endif | ||||
|  | ||||
| 	if (n != 1) | ||||
| 		return -1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										413
									
								
								Kinc/Sources/kinc/libs/tls/openssl/lws-genrsa.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										413
									
								
								Kinc/Sources/kinc/libs/tls/openssl/lws-genrsa.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,413 @@ | ||||
|  /* | ||||
|  * libwebsockets - small server side websockets and web server implementation | ||||
|  * | ||||
|  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to | ||||
|  * deal in the Software without restriction, including without limitation the | ||||
|  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
|  * sell copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|  * IN THE SOFTWARE. | ||||
|  * | ||||
|  *  lws_genrsa provides an RSA abstraction api in lws that works the | ||||
|  *  same whether you are using openssl or mbedtls crypto functions underneath. | ||||
|  */ | ||||
| #include "private-lib-core.h" | ||||
| #include "private-lib-tls-openssl.h" | ||||
|  | ||||
| /* | ||||
|  * Care: many openssl apis return 1 for success.  These are translated to the | ||||
|  * lws convention of 0 for success. | ||||
|  */ | ||||
|  | ||||
| void | ||||
| lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el) | ||||
| { | ||||
| 	lws_gencrypto_destroy_elements(el, LWS_GENCRYPTO_RSA_KEYEL_COUNT); | ||||
| } | ||||
|  | ||||
| static int mode_map_crypt[] = { RSA_PKCS1_PADDING, RSA_PKCS1_OAEP_PADDING }, | ||||
| 	   mode_map_sig[]   = { RSA_PKCS1_PADDING, RSA_PKCS1_PSS_PADDING }; | ||||
|  | ||||
| static int | ||||
| rsa_pkey_wrap(struct lws_genrsa_ctx *ctx, RSA *rsa) | ||||
| { | ||||
| 	EVP_PKEY *pkey; | ||||
|  | ||||
| 	/* we have the RSA object filled up... wrap in a PKEY */ | ||||
|  | ||||
| 	pkey = EVP_PKEY_new(); | ||||
| 	if (!pkey) | ||||
| 		return 1; | ||||
|  | ||||
| 	/* bind the PKEY to the RSA key we just prepared */ | ||||
|  | ||||
| 	if (EVP_PKEY_assign_RSA(pkey, rsa) != 1) { | ||||
| 		lwsl_err("%s: EVP_PKEY_assign_RSA_KEY failed\n", __func__); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	/* pepare our PKEY_CTX with the PKEY */ | ||||
|  | ||||
| 	ctx->ctx = EVP_PKEY_CTX_new(pkey, NULL); | ||||
| 	EVP_PKEY_free(pkey); | ||||
| 	pkey = NULL; | ||||
| 	if (!ctx->ctx) | ||||
| 		goto bail; | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| bail: | ||||
| 	if (pkey) | ||||
| 		EVP_PKEY_free(pkey); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genrsa_create(struct lws_genrsa_ctx *ctx, | ||||
| 		  const struct lws_gencrypto_keyelem *el, | ||||
| 		  struct lws_context *context, enum enum_genrsa_mode mode, | ||||
| 		  enum lws_genhash_types oaep_hashid) | ||||
| { | ||||
| 	int n; | ||||
|  | ||||
| 	memset(ctx, 0, sizeof(*ctx)); | ||||
| 	ctx->context = context; | ||||
| 	ctx->mode = mode; | ||||
|  | ||||
| 	/* Step 1: | ||||
| 	 * | ||||
| 	 * convert the MPI for e and n to OpenSSL BIGNUMs | ||||
| 	 */ | ||||
|  | ||||
| 	for (n = 0; n < 5; n++) { | ||||
| 		ctx->bn[n] = BN_bin2bn(el[n].buf, (int)el[n].len, NULL); | ||||
| 		if (!ctx->bn[n]) { | ||||
| 			lwsl_notice("mpi load failed\n"); | ||||
| 			goto bail; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Step 2: | ||||
| 	 * | ||||
| 	 * assemble the OpenSSL RSA from the BIGNUMs | ||||
| 	 */ | ||||
|  | ||||
| 	ctx->rsa = RSA_new(); | ||||
| 	if (!ctx->rsa) { | ||||
| 		lwsl_notice("Failed to create RSA\n"); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| #if defined(LWS_HAVE_RSA_SET0_KEY) && !defined(USE_WOLFSSL)  | ||||
| 	if (RSA_set0_key(ctx->rsa, ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_N], | ||||
| 			 ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_E], | ||||
| 			 ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_D]) != 1) { | ||||
| 		lwsl_notice("RSA_set0_key failed\n"); | ||||
| 		goto bail; | ||||
| 	} | ||||
| 	RSA_set0_factors(ctx->rsa, ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_P], | ||||
| 				   ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_Q]); | ||||
| #else | ||||
| 	ctx->rsa->e = ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_E]; | ||||
| 	ctx->rsa->n = ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_N]; | ||||
| 	ctx->rsa->d = ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_D]; | ||||
| 	ctx->rsa->p = ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_P]; | ||||
| 	ctx->rsa->q = ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_Q]; | ||||
| #endif | ||||
|  | ||||
| 	if (!rsa_pkey_wrap(ctx, ctx->rsa)) | ||||
| 		return 0; | ||||
|  | ||||
| bail: | ||||
| 	for (n = 0; n < 5; n++) | ||||
| 		if (ctx->bn[n]) { | ||||
| 			BN_clear_free(ctx->bn[n]); | ||||
| 			ctx->bn[n] = NULL; | ||||
| 		} | ||||
|  | ||||
| 	if (ctx->rsa) { | ||||
| 		RSA_free(ctx->rsa); | ||||
| 		ctx->rsa = NULL; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx, | ||||
| 		       enum enum_genrsa_mode mode, struct lws_gencrypto_keyelem *el, | ||||
| 		       int bits) | ||||
| { | ||||
| 	BIGNUM *bn; | ||||
| 	int n; | ||||
|  | ||||
| 	memset(ctx, 0, sizeof(*ctx)); | ||||
| 	ctx->context = context; | ||||
| 	ctx->mode = mode; | ||||
|  | ||||
| 	ctx->rsa = RSA_new(); | ||||
| 	if (!ctx->rsa) { | ||||
| 		lwsl_notice("Failed to create RSA\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	bn = BN_new(); | ||||
| 	if (!bn) | ||||
| 		goto cleanup_1; | ||||
| 	if (BN_set_word(bn, RSA_F4) != 1) { | ||||
| 		BN_free(bn); | ||||
| 		goto cleanup_1; | ||||
| 	} | ||||
|  | ||||
| 	n = RSA_generate_key_ex(ctx->rsa, bits, bn, NULL); | ||||
| 	BN_clear_free(bn); | ||||
| 	if (n != 1) | ||||
| 		goto cleanup_1; | ||||
|  | ||||
| #if defined(LWS_HAVE_RSA_SET0_KEY) && !defined(USE_WOLFSSL) | ||||
| 	{ | ||||
| 		const BIGNUM *mpi[5]; | ||||
|  | ||||
| 		RSA_get0_key(ctx->rsa, &mpi[LWS_GENCRYPTO_RSA_KEYEL_N], | ||||
| 			     &mpi[LWS_GENCRYPTO_RSA_KEYEL_E], &mpi[LWS_GENCRYPTO_RSA_KEYEL_D]); | ||||
| 		RSA_get0_factors(ctx->rsa, &mpi[LWS_GENCRYPTO_RSA_KEYEL_P], | ||||
| 				 &mpi[LWS_GENCRYPTO_RSA_KEYEL_Q]); | ||||
| #else | ||||
| 	{ | ||||
| 		BIGNUM *mpi[5] = { ctx->rsa->e, ctx->rsa->n, ctx->rsa->d, | ||||
| 				   ctx->rsa->p, ctx->rsa->q, }; | ||||
| #endif | ||||
| 		for (n = 0; n < 5; n++) | ||||
| 			if (BN_num_bytes(mpi[n])) { | ||||
| 				el[n].buf = lws_malloc( | ||||
| 					(unsigned int)BN_num_bytes(mpi[n]), "genrsakey"); | ||||
| 				if (!el[n].buf) | ||||
| 					goto cleanup; | ||||
| 				el[n].len = (unsigned int)BN_num_bytes(mpi[n]); | ||||
| 				BN_bn2bin(mpi[n], el[n].buf); | ||||
| 			} | ||||
| 	} | ||||
|  | ||||
| 	if (!rsa_pkey_wrap(ctx, ctx->rsa)) | ||||
| 		return 0; | ||||
|  | ||||
| cleanup: | ||||
| 	for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++) | ||||
| 		if (el[n].buf) | ||||
| 			lws_free_set_NULL(el[n].buf); | ||||
| cleanup_1: | ||||
| 	RSA_free(ctx->rsa); | ||||
| 	ctx->rsa = NULL; | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * in_len must be less than RSA_size(rsa) - 11 for the PKCS #1 v1.5 | ||||
|  * based padding modes | ||||
|  */ | ||||
|  | ||||
| int | ||||
| lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, | ||||
| 			  size_t in_len, uint8_t *out) | ||||
| { | ||||
| 	int n = RSA_public_encrypt((int)in_len, in, out, ctx->rsa, | ||||
| 				   mode_map_crypt[ctx->mode]); | ||||
| 	if (n < 0) { | ||||
| 		lwsl_err("%s: RSA_public_encrypt failed\n", __func__); | ||||
| 		lws_tls_err_describe_clear(); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genrsa_private_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, | ||||
| 			   size_t in_len, uint8_t *out) | ||||
| { | ||||
| 	int n = RSA_private_encrypt((int)in_len, in, out, ctx->rsa, | ||||
| 			        mode_map_crypt[ctx->mode]); | ||||
| 	if (n < 0) { | ||||
| 		lwsl_err("%s: RSA_private_encrypt failed\n", __func__); | ||||
| 		lws_tls_err_describe_clear(); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, | ||||
| 			  size_t in_len, uint8_t *out, size_t out_max) | ||||
| { | ||||
| 	int n = RSA_public_decrypt((int)in_len, in, out, ctx->rsa, | ||||
| 			       mode_map_crypt[ctx->mode]); | ||||
| 	if (n < 0) { | ||||
| 		lwsl_err("%s: RSA_public_decrypt failed\n", __func__); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genrsa_private_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, | ||||
| 			   size_t in_len, uint8_t *out, size_t out_max) | ||||
| { | ||||
| 	int n = RSA_private_decrypt((int)in_len, in, out, ctx->rsa, | ||||
| 			        mode_map_crypt[ctx->mode]); | ||||
| 	if (n < 0) { | ||||
| 		lwsl_err("%s: RSA_private_decrypt failed\n", __func__); | ||||
| 		lws_tls_err_describe_clear(); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in, | ||||
| 			 enum lws_genhash_types hash_type, const uint8_t *sig, | ||||
| 			 size_t sig_len) | ||||
| { | ||||
| 	int n = lws_gencrypto_openssl_hash_to_NID(hash_type), | ||||
| 	    h = (int)lws_genhash_size(hash_type); | ||||
| 	const EVP_MD *md = NULL; | ||||
|  | ||||
| 	if (n < 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	switch(ctx->mode) { | ||||
| 	case LGRSAM_PKCS1_1_5: | ||||
| 		n = RSA_verify(n, in, (unsigned int)h, (uint8_t *)sig, | ||||
| 			       (unsigned int)sig_len, ctx->rsa); | ||||
| 		break; | ||||
| 	case LGRSAM_PKCS1_OAEP_PSS: | ||||
| 		md = lws_gencrypto_openssl_hash_to_EVP_MD(hash_type); | ||||
| 		if (!md) | ||||
| 			return -1; | ||||
|  | ||||
| #if defined(LWS_HAVE_RSA_verify_pss_mgf1) | ||||
| 		n = RSA_verify_pss_mgf1(ctx->rsa, in, h, md, NULL, -1, | ||||
| 					(uint8_t *)sig, | ||||
| #else | ||||
| 		n = RSA_verify_PKCS1_PSS(ctx->rsa, in, md, (uint8_t *)sig, | ||||
| #endif | ||||
| 					 (int)sig_len); | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (n != 1) { | ||||
| 		lwsl_notice("%s: fail\n", __func__); | ||||
| 		lws_tls_err_describe_clear(); | ||||
|  | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_genrsa_hash_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in, | ||||
| 		       enum lws_genhash_types hash_type, uint8_t *sig, | ||||
| 		       size_t sig_len) | ||||
| { | ||||
| 	int n = lws_gencrypto_openssl_hash_to_NID(hash_type), | ||||
| 	    h = (int)lws_genhash_size(hash_type); | ||||
| 	unsigned int used = 0; | ||||
| 	EVP_MD_CTX *mdctx = NULL; | ||||
| 	const EVP_MD *md = NULL; | ||||
|  | ||||
| 	if (n < 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	switch(ctx->mode) { | ||||
| 	case LGRSAM_PKCS1_1_5: | ||||
| 		if (RSA_sign(n, in, (unsigned int)h, sig, &used, ctx->rsa) != 1) { | ||||
| 			lwsl_err("%s: RSA_sign failed\n", __func__); | ||||
|  | ||||
| 			goto bail; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case LGRSAM_PKCS1_OAEP_PSS: | ||||
|  | ||||
| 		md = lws_gencrypto_openssl_hash_to_EVP_MD(hash_type); | ||||
| 		if (!md) | ||||
| 			return -1; | ||||
|  | ||||
| 		if (EVP_PKEY_CTX_set_rsa_padding(ctx->ctx, | ||||
| 						 mode_map_sig[ctx->mode]) != 1) { | ||||
| 			lwsl_err("%s: set_rsa_padding failed\n", __func__); | ||||
|  | ||||
| 			goto bail; | ||||
| 		} | ||||
|  | ||||
| 		mdctx = EVP_MD_CTX_create(); | ||||
| 		if (!mdctx) | ||||
| 			goto bail; | ||||
|  | ||||
| 		if (EVP_DigestSignInit(mdctx, NULL, md, NULL, | ||||
| #if defined(USE_WOLFSSL) | ||||
| 					ctx->ctx->pkey)) { | ||||
| #else | ||||
| 				       EVP_PKEY_CTX_get0_pkey(ctx->ctx))) { | ||||
| #endif | ||||
| 			lwsl_err("%s: EVP_DigestSignInit failed\n", __func__); | ||||
|  | ||||
| 			goto bail; | ||||
| 		} | ||||
| 		if (EVP_DigestSignUpdate(mdctx, in, (unsigned int)EVP_MD_size(md))) { | ||||
| 			lwsl_err("%s: EVP_DigestSignUpdate failed\n", __func__); | ||||
|  | ||||
| 			goto bail; | ||||
| 		} | ||||
| 		if (EVP_DigestSignFinal(mdctx, sig, &sig_len)) { | ||||
| 			lwsl_err("%s: EVP_DigestSignFinal failed\n", __func__); | ||||
|  | ||||
| 			goto bail; | ||||
| 		} | ||||
| 		EVP_MD_CTX_free(mdctx); | ||||
| 		used = (unsigned int)sig_len; | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return (int)used; | ||||
|  | ||||
| bail: | ||||
| 	if (mdctx) | ||||
| 		EVP_MD_CTX_free(mdctx); | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| void | ||||
| lws_genrsa_destroy(struct lws_genrsa_ctx *ctx) | ||||
| { | ||||
| 	if (!ctx->ctx) | ||||
| 		return; | ||||
|  | ||||
| 	EVP_PKEY_CTX_free(ctx->ctx); | ||||
| 	ctx->ctx = NULL; | ||||
| 	ctx->rsa = NULL; | ||||
| } | ||||
							
								
								
									
										1242
									
								
								Kinc/Sources/kinc/libs/tls/openssl/openssl-client.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1242
									
								
								Kinc/Sources/kinc/libs/tls/openssl/openssl-client.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1139
									
								
								Kinc/Sources/kinc/libs/tls/openssl/openssl-server.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1139
									
								
								Kinc/Sources/kinc/libs/tls/openssl/openssl-server.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										491
									
								
								Kinc/Sources/kinc/libs/tls/openssl/openssl-session.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										491
									
								
								Kinc/Sources/kinc/libs/tls/openssl/openssl-session.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,491 @@ | ||||
| /* | ||||
|  * libwebsockets - small server side websockets and web server implementation | ||||
|  * | ||||
|  * Copyright (C) 2010 - 2022 Andy Green <andy@warmcat.com> | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to | ||||
|  * deal in the Software without restriction, including without limitation the | ||||
|  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
|  * sell copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|  * IN THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include "private-lib-core.h" | ||||
|  | ||||
| typedef struct lws_tls_session_cache_openssl { | ||||
| 	lws_dll2_t			list; | ||||
|  | ||||
| 	SSL_SESSION			*session; | ||||
| 	lws_sorted_usec_list_t		sul_ttl; | ||||
|  | ||||
| 	/* name is overallocated here */ | ||||
| } lws_tls_sco_t; | ||||
|  | ||||
| #define tlssess_loglevel		LLL_INFO | ||||
| #if (_LWS_ENABLED_LOGS & tlssess_loglevel) | ||||
| #define lwsl_tlssess(...)		_lws_log(tlssess_loglevel, __VA_ARGS__) | ||||
| #else | ||||
| #define lwsl_tlssess(...) | ||||
| #endif | ||||
|  | ||||
| static void | ||||
| __lws_tls_session_destroy(lws_tls_sco_t *ts) | ||||
| { | ||||
| 	lwsl_tlssess("%s: %s (%u)\n", __func__, (const char *)&ts[1], | ||||
| 				     ts->list.owner->count - 1); | ||||
|  | ||||
| 	lws_sul_cancel(&ts->sul_ttl); | ||||
| 	SSL_SESSION_free(ts->session); | ||||
| 	lws_dll2_remove(&ts->list);		/* vh lock */ | ||||
|  | ||||
| 	lws_free(ts); | ||||
| } | ||||
|  | ||||
| static lws_tls_sco_t * | ||||
| __lws_tls_session_lookup_by_name(struct lws_vhost *vh, const char *name) | ||||
| { | ||||
| 	lws_start_foreach_dll(struct lws_dll2 *, p, | ||||
| 			      lws_dll2_get_head(&vh->tls_sessions)) { | ||||
| 		lws_tls_sco_t *ts = lws_container_of(p, lws_tls_sco_t, list); | ||||
| 		const char *ts_name = (const char *)&ts[1]; | ||||
|  | ||||
| 		if (!strcmp(name, ts_name)) | ||||
| 			return ts; | ||||
|  | ||||
| 	} lws_end_foreach_dll(p); | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * If possible, reuse an existing, cached session | ||||
|  */ | ||||
|  | ||||
| void | ||||
| lws_tls_reuse_session(struct lws *wsi) | ||||
| { | ||||
| 	char tag[LWS_SESSION_TAG_LEN]; | ||||
| 	lws_tls_sco_t *ts; | ||||
|  | ||||
| 	if (!wsi->a.vhost || | ||||
| 	    wsi->a.vhost->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE) | ||||
| 		return; | ||||
|  | ||||
| 	lws_context_lock(wsi->a.context, __func__); /* -------------- cx { */ | ||||
| 	lws_vhost_lock(wsi->a.vhost); /* -------------- vh { */ | ||||
|  | ||||
| 	if (lws_tls_session_tag_from_wsi(wsi, tag, sizeof(tag))) | ||||
| 		goto bail; | ||||
| 	ts = __lws_tls_session_lookup_by_name(wsi->a.vhost, tag); | ||||
|  | ||||
| 	if (!ts) { | ||||
| 		lwsl_tlssess("%s: no existing session for %s\n", __func__, tag); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	lwsl_tlssess("%s: %s\n", __func__, (const char *)&ts[1]); | ||||
|  | ||||
| 	if (!SSL_set_session(wsi->tls.ssl, ts->session)) { | ||||
| 		lwsl_err("%s: session not set for %s\n", __func__, tag); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| #if !defined(USE_WOLFSSL) | ||||
| 	/* extend session lifetime */ | ||||
| 	SSL_SESSION_set_time(ts->session, | ||||
| #if defined(OPENSSL_IS_BORINGSSL) | ||||
| 			(unsigned long) | ||||
| #else | ||||
| 			(long) | ||||
| #endif | ||||
| 			time(NULL)); | ||||
| #endif | ||||
|  | ||||
| 	/* keep our session list sorted in lru -> mru order */ | ||||
|  | ||||
| 	lws_dll2_remove(&ts->list); | ||||
| 	lws_dll2_add_tail(&ts->list, &wsi->a.vhost->tls_sessions); | ||||
|  | ||||
| bail: | ||||
| 	lws_vhost_unlock(wsi->a.vhost); /* } vh --------------  */ | ||||
| 	lws_context_unlock(wsi->a.context); /* } cx --------------  */ | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_tls_session_is_reused(struct lws *wsi) | ||||
| { | ||||
| #if defined(LWS_WITH_CLIENT) | ||||
| 	struct lws *nwsi = lws_get_network_wsi(wsi); | ||||
|  | ||||
| 	if (!nwsi || !nwsi->tls.ssl) | ||||
| 		return 0; | ||||
|  | ||||
|        return (int)SSL_session_reused(nwsi->tls.ssl); | ||||
| #else | ||||
|        return 0; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static int | ||||
| lws_tls_session_destroy_dll(struct lws_dll2 *d, void *user) | ||||
| { | ||||
| 	lws_tls_sco_t *ts = lws_container_of(d, lws_tls_sco_t, list); | ||||
|  | ||||
| 	__lws_tls_session_destroy(ts); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| lws_tls_session_vh_destroy(struct lws_vhost *vh) | ||||
| { | ||||
| 	lws_dll2_foreach_safe(&vh->tls_sessions, NULL, | ||||
| 			      lws_tls_session_destroy_dll); | ||||
| } | ||||
|  | ||||
| static void | ||||
| lws_tls_session_expiry_cb(lws_sorted_usec_list_t *sul) | ||||
| { | ||||
| 	lws_tls_sco_t *ts = lws_container_of(sul, lws_tls_sco_t, sul_ttl); | ||||
| 	struct lws_vhost *vh = lws_container_of(ts->list.owner, | ||||
| 						struct lws_vhost, tls_sessions); | ||||
|  | ||||
| 	lws_context_lock(vh->context, __func__); /* -------------- cx { */ | ||||
| 	lws_vhost_lock(vh); /* -------------- vh { */ | ||||
| 	__lws_tls_session_destroy(ts); | ||||
| 	lws_vhost_unlock(vh); /* } vh --------------  */ | ||||
| 	lws_context_unlock(vh->context); /* } cx --------------  */ | ||||
| } | ||||
|  | ||||
| static lws_tls_sco_t * | ||||
| lws_tls_session_add_entry(struct lws_vhost *vh, const char *tag) | ||||
| { | ||||
| 	lws_tls_sco_t *ts; | ||||
| 	size_t nl = strlen(tag); | ||||
|  | ||||
| 	if (vh->tls_sessions.count == (vh->tls_session_cache_max ? | ||||
| 				      vh->tls_session_cache_max : 10)) { | ||||
|  | ||||
| 		/* | ||||
| 		 * We have reached the vhost's session cache limit, | ||||
| 		 * prune the LRU / head | ||||
| 		 */ | ||||
| 		ts = lws_container_of(vh->tls_sessions.head, | ||||
| 				      lws_tls_sco_t, list); | ||||
|  | ||||
| 		if (ts) { /* centos 7 ... */ | ||||
| 			lwsl_tlssess("%s: pruning oldest session\n", __func__); | ||||
|  | ||||
| 			lws_vhost_lock(vh); /* -------------- vh { */ | ||||
| 			__lws_tls_session_destroy(ts); | ||||
| 			lws_vhost_unlock(vh); /* } vh --------------  */ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	ts = lws_malloc(sizeof(*ts) + nl + 1, __func__); | ||||
|  | ||||
| 	if (!ts) | ||||
| 		return NULL; | ||||
|  | ||||
| 	memset(ts, 0, sizeof(*ts)); | ||||
| 	memcpy(&ts[1], tag, nl + 1); | ||||
|  | ||||
| 	lws_dll2_add_tail(&ts->list, &vh->tls_sessions); | ||||
|  | ||||
| 	return ts; | ||||
| } | ||||
|  | ||||
| static int | ||||
| lws_tls_session_new_cb(SSL *ssl, SSL_SESSION *sess) | ||||
| { | ||||
| 	struct lws *wsi = (struct lws *)SSL_get_ex_data(ssl, | ||||
| 					openssl_websocket_private_data_index); | ||||
| 	char tag[LWS_SESSION_TAG_LEN]; | ||||
| 	struct lws_vhost *vh; | ||||
| 	lws_tls_sco_t *ts; | ||||
| 	long ttl; | ||||
| #if (_LWS_ENABLED_LOGS & tlssess_loglevel) | ||||
| 	const char *disposition = "reuse"; | ||||
| #endif | ||||
|  | ||||
| 	if (!wsi) { | ||||
| 		lwsl_warn("%s: can't get wsi from ssl privdata\n", __func__); | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	vh = wsi->a.vhost; | ||||
| 	if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (lws_tls_session_tag_from_wsi(wsi, tag, sizeof(tag))) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* api return is long, although we only support setting | ||||
| 	 * default (300s) or max uint32_t */ | ||||
| 	ttl = SSL_SESSION_get_timeout(sess); | ||||
|  | ||||
| 	lws_context_lock(vh->context, __func__); /* -------------- cx { */ | ||||
| 	lws_vhost_lock(vh); /* -------------- vh { */ | ||||
|  | ||||
| 	ts = __lws_tls_session_lookup_by_name(vh, tag); | ||||
|  | ||||
| 	if (!ts) { | ||||
| 		ts = lws_tls_session_add_entry(vh, tag); | ||||
|  | ||||
| 		if (!ts) | ||||
| 			goto bail; | ||||
|  | ||||
| 		lws_sul_schedule(wsi->a.context, wsi->tsi, &ts->sul_ttl, | ||||
| 				 lws_tls_session_expiry_cb, | ||||
| 				 ttl * LWS_US_PER_SEC); | ||||
|  | ||||
| #if (_LWS_ENABLED_LOGS & tlssess_loglevel) | ||||
| 		disposition = "new"; | ||||
| #endif | ||||
|  | ||||
| 		/* | ||||
| 		 * We don't have to do a SSL_SESSION_up_ref() here, because | ||||
| 		 * we will return from this callback indicating that we kept the | ||||
| 		 * ref | ||||
| 		 */ | ||||
| 	} else { | ||||
| 		/* | ||||
| 		 * Give up our refcount on the session we are about to replace | ||||
| 		 * with a newer one | ||||
| 		 */ | ||||
| 		SSL_SESSION_free(ts->session); | ||||
|  | ||||
| 		/* keep our session list sorted in lru -> mru order */ | ||||
|  | ||||
| 		lws_dll2_remove(&ts->list); | ||||
| 		lws_dll2_add_tail(&ts->list, &vh->tls_sessions); | ||||
| 	} | ||||
|  | ||||
| 	ts->session = sess; | ||||
|  | ||||
| 	lws_vhost_unlock(vh); /* } vh --------------  */ | ||||
| 	lws_context_unlock(vh->context); /* } cx --------------  */ | ||||
|  | ||||
| 	lwsl_tlssess("%s: %p: %s: %s %s, ttl %lds (%s:%u)\n", __func__, | ||||
| 		     sess, wsi->lc.gutag, disposition, tag, ttl, vh->name, | ||||
| 		     vh->tls_sessions.count); | ||||
|  | ||||
| 	/* | ||||
| 	 * indicate we will hold on to the SSL_SESSION reference, and take | ||||
| 	 * responsibility to call SSL_SESSION_free() on it ourselves | ||||
| 	 */ | ||||
|  | ||||
| 	return 1; | ||||
|  | ||||
| bail: | ||||
| 	lws_vhost_unlock(vh); /* } vh --------------  */ | ||||
| 	lws_context_unlock(vh->context); /* } cx --------------  */ | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #if defined(LWS_TLS_SYNTHESIZE_CB) | ||||
|  | ||||
| /* | ||||
|  * On openssl, there is an async cb coming when the server issues the session | ||||
|  * information on the link, so we can pick it up and update the cache at the | ||||
|  * right time. | ||||
|  * | ||||
|  * On mbedtls and some version at least of borning ssl, this cb is either not | ||||
|  * part of the tls library apis or fails to arrive. | ||||
|  * | ||||
|  * This synthetic cb is called instead for those build cases, scheduled for | ||||
|  * +500ms after the tls negotiation completed. | ||||
|  */ | ||||
|  | ||||
| void | ||||
| lws_sess_cache_synth_cb(lws_sorted_usec_list_t *sul) | ||||
| { | ||||
| 	struct lws_lws_tls *tls = lws_container_of(sul, struct lws_lws_tls, | ||||
| 						   sul_cb_synth); | ||||
| 	struct lws *wsi = lws_container_of(tls, struct lws, tls); | ||||
| 	SSL_SESSION *sess; | ||||
|  | ||||
| 	if (lws_tls_session_is_reused(wsi)) | ||||
| 		return; | ||||
|  | ||||
| 	sess = SSL_get1_session(tls->ssl); | ||||
| 	if (!sess) | ||||
| 		return; | ||||
|  | ||||
| 	if (!SSL_SESSION_is_resumable(sess) || /* not worth caching, or... */ | ||||
| 	    !lws_tls_session_new_cb(tls->ssl, sess)) { /* ...cb didn't keep it */ | ||||
| 		/* | ||||
| 		 * For now the policy if no session message after the wait, | ||||
| 		 * is just let it be.  Typically the session info is sent | ||||
| 		 * early. | ||||
| 		 */ | ||||
| 		SSL_SESSION_free(sess); | ||||
| 	} | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void | ||||
| lws_tls_session_cache(struct lws_vhost *vh, uint32_t ttl) | ||||
| { | ||||
| 	long cmode; | ||||
|  | ||||
| 	if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE) | ||||
| 		return; | ||||
|  | ||||
| 	cmode = SSL_CTX_get_session_cache_mode(vh->tls.ssl_client_ctx); | ||||
|  | ||||
| 	SSL_CTX_set_session_cache_mode(vh->tls.ssl_client_ctx, | ||||
| 				       (int)(cmode | SSL_SESS_CACHE_CLIENT)); | ||||
|  | ||||
| 	SSL_CTX_sess_set_new_cb(vh->tls.ssl_client_ctx, lws_tls_session_new_cb); | ||||
|  | ||||
| 	if (!ttl) | ||||
| 		return; | ||||
|  | ||||
| #if defined(OPENSSL_IS_BORINGSSL) | ||||
| 	SSL_CTX_set_timeout(vh->tls.ssl_client_ctx, ttl); | ||||
| #else | ||||
| 	SSL_CTX_set_timeout(vh->tls.ssl_client_ctx, (long)ttl); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_tls_session_dump_save(struct lws_vhost *vh, const char *host, uint16_t port, | ||||
| 			  lws_tls_sess_cb_t cb_save, void *opq) | ||||
| { | ||||
| 	struct lws_tls_session_dump d; | ||||
| 	lws_tls_sco_t *ts; | ||||
| 	int ret = 1, bl; | ||||
| 	void *v; | ||||
|  | ||||
| 	if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE) | ||||
| 		return 1; | ||||
|  | ||||
| 	lws_tls_session_tag_discrete(vh->name, host, port, d.tag, sizeof(d.tag)); | ||||
|  | ||||
| 	lws_context_lock(vh->context, __func__); /* -------------- cx { */ | ||||
| 	lws_vhost_lock(vh); /* -------------- vh { */ | ||||
|  | ||||
| 	ts = __lws_tls_session_lookup_by_name(vh, d.tag); | ||||
| 	if (!ts) | ||||
| 		goto bail; | ||||
|  | ||||
| 	/* We have a ref on the session, exit via bail to clean it... */ | ||||
|  | ||||
| 	bl = i2d_SSL_SESSION(ts->session, NULL); | ||||
| 	if (!bl) | ||||
| 		goto bail; | ||||
|  | ||||
| 	d.blob_len = (size_t)bl; | ||||
| 	v = d.blob = lws_malloc(d.blob_len, __func__); | ||||
|  | ||||
| 	if (d.blob) { | ||||
|  | ||||
| 		/* this advances d.blob by the blob size ;-) */ | ||||
| 		i2d_SSL_SESSION(ts->session, (uint8_t **)&d.blob); | ||||
|  | ||||
| 		d.opaque = opq; | ||||
| 		d.blob = v; | ||||
| 		if (cb_save(vh->context, &d)) | ||||
| 			lwsl_notice("%s: save failed\n", __func__); | ||||
| 		else | ||||
| 			ret = 0; | ||||
|  | ||||
| 		lws_free(v); | ||||
| 	} | ||||
|  | ||||
| bail: | ||||
| 	lws_vhost_unlock(vh); /* } vh --------------  */ | ||||
| 	lws_context_unlock(vh->context); /* } cx --------------  */ | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_tls_session_dump_load(struct lws_vhost *vh, const char *host, uint16_t port, | ||||
| 			  lws_tls_sess_cb_t cb_load, void *opq) | ||||
| { | ||||
| 	struct lws_tls_session_dump d; | ||||
| 	lws_tls_sco_t *ts; | ||||
| 	SSL_SESSION *sess = NULL; /* allow it to "bail" early */ | ||||
| 	void *v; | ||||
|  | ||||
| 	if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE) | ||||
| 		return 1; | ||||
|  | ||||
| 	d.opaque = opq; | ||||
| 	lws_tls_session_tag_discrete(vh->name, host, port, d.tag, sizeof(d.tag)); | ||||
|  | ||||
| 	lws_context_lock(vh->context, __func__); /* -------------- cx { */ | ||||
| 	lws_vhost_lock(vh); /* -------------- vh { */ | ||||
|  | ||||
| 	ts = __lws_tls_session_lookup_by_name(vh, d.tag); | ||||
|  | ||||
| 	if (ts) { | ||||
| 		/* | ||||
| 		 * Since we are getting this out of cold storage, we should | ||||
| 		 * not replace any existing session since it is likely newer | ||||
| 		 */ | ||||
| 		lwsl_notice("%s: session already exists for %s\n", __func__, | ||||
| 				d.tag); | ||||
| 		goto bail1; | ||||
| 	} | ||||
|  | ||||
| 	if (cb_load(vh->context, &d)) { | ||||
| 		lwsl_warn("%s: load failed\n", __func__); | ||||
|  | ||||
| 		goto bail1; | ||||
| 	} | ||||
|  | ||||
| 	/* the callback has allocated the blob and set d.blob / d.blob_len */ | ||||
|  | ||||
| 	v = d.blob; | ||||
| 	/* this advances d.blob by the blob size ;-) */ | ||||
| 	sess = d2i_SSL_SESSION(NULL, (const uint8_t **)&d.blob, | ||||
| 							(long)d.blob_len); | ||||
| 	free(v); /* user code will have used malloc() */ | ||||
| 	if (!sess) { | ||||
| 		lwsl_warn("%s: d2i_SSL_SESSION failed\n", __func__); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	lws_vhost_lock(vh); /* -------------- vh { */ | ||||
| 	ts = lws_tls_session_add_entry(vh, d.tag); | ||||
| 	lws_vhost_unlock(vh); /* } vh --------------  */ | ||||
|  | ||||
| 	if (!ts) { | ||||
| 		lwsl_warn("%s: unable to add cache entry\n", __func__); | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	ts->session = sess; | ||||
| 	lwsl_tlssess("%s: session loaded OK\n", __func__); | ||||
|  | ||||
| 	lws_vhost_unlock(vh); /* } vh --------------  */ | ||||
| 	lws_context_unlock(vh->context); /* } cx --------------  */ | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| bail: | ||||
| 	SSL_SESSION_free(sess); | ||||
| bail1: | ||||
|  | ||||
| 	lws_vhost_unlock(vh); /* } vh --------------  */ | ||||
| 	lws_context_unlock(vh->context); /* } cx --------------  */ | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										603
									
								
								Kinc/Sources/kinc/libs/tls/openssl/openssl-ssl.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										603
									
								
								Kinc/Sources/kinc/libs/tls/openssl/openssl-ssl.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,603 @@ | ||||
| /* | ||||
|  * libwebsockets - small server side websockets and web server implementation | ||||
|  * | ||||
|  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to | ||||
|  * deal in the Software without restriction, including without limitation the | ||||
|  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
|  * sell copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|  * IN THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include "private-lib-core.h" | ||||
| #include "private-lib-tls-openssl.h" | ||||
|  | ||||
| int openssl_websocket_private_data_index, | ||||
| 	   openssl_SSL_CTX_private_data_index; | ||||
|  | ||||
| /* | ||||
|  * Care: many openssl apis return 1 for success.  These are translated to the | ||||
|  * lws convention of 0 for success. | ||||
|  */ | ||||
|  | ||||
| int lws_openssl_describe_cipher(struct lws *wsi) | ||||
| { | ||||
| #if !defined(LWS_WITH_NO_LOGS) && !defined(USE_WOLFSSL) | ||||
| 	int np = -1; | ||||
| 	SSL *s = wsi->tls.ssl; | ||||
|  | ||||
| 	SSL_get_cipher_bits(s, &np); | ||||
| 	lwsl_info("%s: %s: %s, %s, %d bits, %s\n", __func__, lws_wsi_tag(wsi), | ||||
| 			SSL_get_cipher_name(s), SSL_get_cipher(s), np, | ||||
| 			SSL_get_cipher_version(s)); | ||||
| #endif | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int lws_ssl_get_error(struct lws *wsi, int n) | ||||
| { | ||||
| 	int m; | ||||
| 	unsigned long l; | ||||
| 	char buf[160]; | ||||
|  | ||||
| 	if (!wsi->tls.ssl) | ||||
| 		return 99; | ||||
|  | ||||
| 	m = SSL_get_error(wsi->tls.ssl, n); | ||||
|        lwsl_debug("%s: %p %d -> %d (errno %d)\n", __func__, wsi->tls.ssl, n, m, LWS_ERRNO); | ||||
| 	if (m == SSL_ERROR_SSL) { | ||||
| 		if (!wsi->tls.err_helper[0]) { | ||||
| 			/* Append first error for clarity */ | ||||
| 			l = ERR_get_error(); | ||||
| 			if (l) { | ||||
| 				ERR_error_string_n( | ||||
| #if defined(LWS_WITH_BORINGSSL) | ||||
| 					(uint32_t) | ||||
| #endif | ||||
| 					l, buf, sizeof(buf) - 1); | ||||
| 				buf[sizeof(buf) - 1] = '\0'; | ||||
| 				lws_strncpy(wsi->tls.err_helper, buf, | ||||
| 					    sizeof(wsi->tls.err_helper)); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Describe other errors | ||||
| 		lws_tls_err_describe_clear(); | ||||
| 	} | ||||
|  | ||||
|        // assert (LWS_ERRNO != 9); | ||||
|  | ||||
| 	return m; | ||||
| } | ||||
|  | ||||
| #if defined(LWS_WITH_SERVER) | ||||
| static int | ||||
| lws_context_init_ssl_pem_passwd_cb(char *buf, int size, int rwflag, | ||||
| 				   void *userdata) | ||||
| { | ||||
| 	struct lws_context_creation_info * info = | ||||
| 			(struct lws_context_creation_info *)userdata; | ||||
|  | ||||
| 	strncpy(buf, info->ssl_private_key_password, (unsigned int)size); | ||||
| 	buf[size - 1] = '\0'; | ||||
|  | ||||
| 	return (int)strlen(buf); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #if defined(LWS_WITH_CLIENT) | ||||
| static int | ||||
| lws_context_init_ssl_pem_passwd_client_cb(char *buf, int size, int rwflag, | ||||
| 					  void *userdata) | ||||
| { | ||||
| 	struct lws_context_creation_info * info = | ||||
| 			(struct lws_context_creation_info *)userdata; | ||||
| 	const char *p = info->ssl_private_key_password; | ||||
|  | ||||
| 	if (info->client_ssl_private_key_password) | ||||
| 		p = info->client_ssl_private_key_password; | ||||
|  | ||||
| 	strncpy(buf, p, (unsigned int)size); | ||||
| 	buf[size - 1] = '\0'; | ||||
|  | ||||
| 	return (int)strlen(buf); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void | ||||
| lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, int is_client, | ||||
| 			const struct lws_context_creation_info *info) | ||||
| { | ||||
| 	if ( | ||||
| #if defined(LWS_WITH_SERVER) | ||||
| 		!info->ssl_private_key_password | ||||
| #endif | ||||
| #if defined(LWS_WITH_SERVER) && defined(LWS_WITH_CLIENT) | ||||
| 			&& | ||||
| #endif | ||||
| #if defined(LWS_WITH_CLIENT) | ||||
| 	    !info->client_ssl_private_key_password | ||||
| #endif | ||||
| 	    ) | ||||
| 		return; | ||||
| 	/* | ||||
| 	 * password provided, set ssl callback and user data | ||||
| 	 * for checking password which will be trigered during | ||||
| 	 * SSL_CTX_use_PrivateKey_file function | ||||
| 	 */ | ||||
| 	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)info); | ||||
| 	SSL_CTX_set_default_passwd_cb(ssl_ctx, is_client ? | ||||
| #if defined(LWS_WITH_CLIENT) | ||||
| 				      lws_context_init_ssl_pem_passwd_client_cb: | ||||
| #else | ||||
| 					NULL: | ||||
| #endif | ||||
| #if defined(LWS_WITH_SERVER) | ||||
| 				      lws_context_init_ssl_pem_passwd_cb | ||||
| #else | ||||
| 				      	NULL | ||||
| #endif | ||||
| 				  ); | ||||
| } | ||||
|  | ||||
| #if defined(LWS_WITH_CLIENT) | ||||
| static void | ||||
| lws_ssl_destroy_client_ctx(struct lws_vhost *vhost) | ||||
| { | ||||
| 	if (vhost->tls.user_supplied_ssl_ctx || !vhost->tls.ssl_client_ctx) | ||||
| 		return; | ||||
|  | ||||
| 	if (vhost->tls.tcr && --vhost->tls.tcr->refcount) | ||||
| 		return; | ||||
|  | ||||
| 	SSL_CTX_free(vhost->tls.ssl_client_ctx); | ||||
| 	vhost->tls.ssl_client_ctx = NULL; | ||||
|  | ||||
| 	vhost->context->tls.count_client_contexts--; | ||||
|  | ||||
| 	if (vhost->tls.tcr) { | ||||
| 		lws_dll2_remove(&vhost->tls.tcr->cc_list); | ||||
| 		lws_free(vhost->tls.tcr); | ||||
| 		vhost->tls.tcr = NULL; | ||||
| 	} | ||||
| } | ||||
| #endif | ||||
| void | ||||
| lws_ssl_destroy(struct lws_vhost *vhost) | ||||
| { | ||||
| 	if (!lws_check_opt(vhost->context->options, | ||||
| 			   LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) | ||||
| 		return; | ||||
|  | ||||
| 	if (vhost->tls.ssl_ctx) | ||||
| 		SSL_CTX_free(vhost->tls.ssl_ctx); | ||||
| #if defined(LWS_WITH_CLIENT) | ||||
| 	lws_ssl_destroy_client_ctx(vhost); | ||||
| #endif | ||||
|  | ||||
| // after 1.1.0 no need | ||||
| #if (OPENSSL_VERSION_NUMBER <  0x10100000) | ||||
| // <= 1.0.1f = old api, 1.0.1g+ = new api | ||||
| #if (OPENSSL_VERSION_NUMBER <= 0x1000106f) || defined(USE_WOLFSSL) | ||||
| 	ERR_remove_state(0); | ||||
| #else | ||||
| #if OPENSSL_VERSION_NUMBER >= 0x1010005f && \ | ||||
|     !defined(LIBRESSL_VERSION_NUMBER) && \ | ||||
|     !defined(OPENSSL_IS_BORINGSSL) | ||||
| 	ERR_remove_thread_state(); | ||||
| #else | ||||
| 	ERR_remove_thread_state(NULL); | ||||
| #endif | ||||
| #endif | ||||
| 	/* not needed after 1.1.0 */ | ||||
| #if  (OPENSSL_VERSION_NUMBER >= 0x10002000) && \ | ||||
|      (OPENSSL_VERSION_NUMBER <= 0x10100000) | ||||
| 	SSL_COMP_free_compression_methods(); | ||||
| #endif | ||||
| 	ERR_free_strings(); | ||||
| 	EVP_cleanup(); | ||||
| 	CRYPTO_cleanup_all_ex_data(); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, size_t len) | ||||
| { | ||||
| 	struct lws_context *context = wsi->a.context; | ||||
| 	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; | ||||
| 	int n = 0, m; | ||||
|  | ||||
| 	if (!wsi->tls.ssl) | ||||
| 		return lws_ssl_capable_read_no_ssl(wsi, buf, len); | ||||
|  | ||||
| #ifndef WIN32 | ||||
| 	errno = 0; | ||||
| #else | ||||
|   WSASetLastError(0); | ||||
| #endif | ||||
| 	ERR_clear_error(); | ||||
| 	n = SSL_read(wsi->tls.ssl, buf, (int)(ssize_t)len); | ||||
| #if defined(LWS_PLAT_FREERTOS) | ||||
| 	if (!n && errno == LWS_ENOTCONN) { | ||||
| 		lwsl_debug("%s: SSL_read ENOTCONN\n", lws_wsi_tag(wsi)); | ||||
| 		return LWS_SSL_CAPABLE_ERROR; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	lwsl_debug("%s: SSL_read says %d\n", lws_wsi_tag(wsi), n); | ||||
| 	/* manpage: returning 0 means connection shut down | ||||
| 	 * | ||||
| 	 * 2018-09-10: https://github.com/openssl/openssl/issues/1903 | ||||
| 	 * | ||||
| 	 * So, in summary, if you get a 0 or -1 return from SSL_read() / | ||||
| 	 * SSL_write(), you should call SSL_get_error(): | ||||
| 	 * | ||||
| 	 *  - If you get back SSL_ERROR_RETURN_ZERO then you know the connection | ||||
| 	 *    has been cleanly shutdown by the peer. To fully close the | ||||
| 	 *    connection you may choose to call SSL_shutdown() to send a | ||||
| 	 *    close_notify back. | ||||
| 	 * | ||||
| 	 *  - If you get back SSL_ERROR_SSL then some kind of internal or | ||||
| 	 *    protocol error has occurred. More details will be on the SSL error | ||||
| 	 *    queue. You can also call SSL_get_shutdown(). If this indicates a | ||||
| 	 *    state of SSL_RECEIVED_SHUTDOWN then you know a fatal alert has | ||||
| 	 *    been received from the peer (if it had been a close_notify then | ||||
| 	 *    SSL_get_error() would have returned SSL_ERROR_RETURN_ZERO). | ||||
| 	 *    SSL_ERROR_SSL is considered fatal - you should not call | ||||
| 	 *    SSL_shutdown() in this case. | ||||
| 	 * | ||||
| 	 *  - If you get back SSL_ERROR_SYSCALL then some kind of fatal (i.e. | ||||
| 	 *    non-retryable) error has occurred in a system call. | ||||
| 	 */ | ||||
| 	if (n <= 0) { | ||||
| 		m = lws_ssl_get_error(wsi, n); | ||||
|                lwsl_debug("%s: ssl err %d errno %d\n", lws_wsi_tag(wsi), m, LWS_ERRNO); | ||||
| 		if (m == SSL_ERROR_ZERO_RETURN) /* cleanly shut down */ | ||||
| 			goto do_err; | ||||
|  | ||||
| 		if (m == SSL_ERROR_SSL) | ||||
| 		    lws_tls_err_describe_clear(); | ||||
|  | ||||
| 		/* hm not retryable.. could be 0 size pkt or error  */ | ||||
|  | ||||
| 		if (m == SSL_ERROR_SSL || m == SSL_ERROR_SYSCALL || | ||||
|         LWS_ERRNO == LWS_ENOTCONN) { | ||||
|  | ||||
| 			/* unclean, eg closed conn */ | ||||
|  | ||||
| 			wsi->socket_is_permanently_unusable = 1; | ||||
| do_err: | ||||
| #if defined(LWS_WITH_SYS_METRICS) | ||||
| 		if (wsi->a.vhost) | ||||
| 			lws_metric_event(wsi->a.vhost->mt_traffic_rx, | ||||
| 					 METRES_NOGO, 0); | ||||
| #endif | ||||
| 			return LWS_SSL_CAPABLE_ERROR; | ||||
| 		} | ||||
|  | ||||
| 		/* retryable? */ | ||||
|  | ||||
| 		if (SSL_want_read(wsi->tls.ssl)) { | ||||
| 			lwsl_debug("%s: WANT_READ\n", __func__); | ||||
| 			lwsl_debug("%s: LWS_SSL_CAPABLE_MORE_SERVICE\n", lws_wsi_tag(wsi)); | ||||
| 			return LWS_SSL_CAPABLE_MORE_SERVICE; | ||||
| 		} | ||||
| 		if (SSL_want_write(wsi->tls.ssl)) { | ||||
| 			lwsl_info("%s: WANT_WRITE\n", __func__); | ||||
| 			lwsl_debug("%s: LWS_SSL_CAPABLE_MORE_SERVICE\n", lws_wsi_tag(wsi)); | ||||
| 			wsi->tls_read_wanted_write = 1; | ||||
| 			lws_callback_on_writable(wsi); | ||||
| 			return LWS_SSL_CAPABLE_MORE_SERVICE; | ||||
| 		} | ||||
|  | ||||
| 		/* keep on trucking it seems */ | ||||
| 	} | ||||
|  | ||||
| #if defined(LWS_TLS_LOG_PLAINTEXT_RX) | ||||
| 	/* | ||||
| 	 * If using openssl type tls library, this is the earliest point for all | ||||
| 	 * paths to dump what was received as decrypted data from the tls tunnel | ||||
| 	 */ | ||||
| 	lwsl_notice("%s: len %d\n", __func__, n); | ||||
| 	lwsl_hexdump_notice(buf, (unsigned int)n); | ||||
| #endif | ||||
|  | ||||
| #if defined(LWS_WITH_SYS_METRICS) | ||||
| 	if (wsi->a.vhost) | ||||
| 		lws_metric_event(wsi->a.vhost->mt_traffic_rx, METRES_GO, (u_mt_t)n); | ||||
| #endif | ||||
|  | ||||
| 	/* | ||||
| 	 * if it was our buffer that limited what we read, | ||||
| 	 * check if SSL has additional data pending inside SSL buffers. | ||||
| 	 * | ||||
| 	 * Because these won't signal at the network layer with POLLIN | ||||
| 	 * and if we don't realize, this data will sit there forever | ||||
| 	 */ | ||||
| 	if (n != (int)(ssize_t)len) | ||||
| 		goto bail; | ||||
| 	if (!wsi->tls.ssl) | ||||
| 		goto bail; | ||||
|  | ||||
| 	if (SSL_pending(wsi->tls.ssl)) { | ||||
| 		if (lws_dll2_is_detached(&wsi->tls.dll_pending_tls)) | ||||
| 			lws_dll2_add_head(&wsi->tls.dll_pending_tls, | ||||
| 					  &pt->tls.dll_pending_tls_owner); | ||||
| 	} else | ||||
| 		__lws_ssl_remove_wsi_from_buffered_list(wsi); | ||||
|  | ||||
| 	return n; | ||||
| bail: | ||||
| 	lws_ssl_remove_wsi_from_buffered_list(wsi); | ||||
|  | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_ssl_pending(struct lws *wsi) | ||||
| { | ||||
| 	if (!wsi->tls.ssl) | ||||
| 		return 0; | ||||
|  | ||||
| 	return SSL_pending(wsi->tls.ssl); | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, size_t len) | ||||
| { | ||||
| 	int n, m; | ||||
|  | ||||
|  | ||||
| #if defined(LWS_TLS_LOG_PLAINTEXT_TX) | ||||
| 	/* | ||||
| 	 * If using OpenSSL type tls library, this is the last point for all | ||||
| 	 * paths before sending data into the tls tunnel, where you can dump it | ||||
| 	 * and see what is being sent. | ||||
| 	 */ | ||||
| 	lwsl_notice("%s: len %u\n", __func__, (unsigned int)len); | ||||
| 	lwsl_hexdump_notice(buf, len); | ||||
| #endif | ||||
|  | ||||
| 	if (!wsi->tls.ssl) | ||||
| 		return lws_ssl_capable_write_no_ssl(wsi, buf, len); | ||||
|  | ||||
| 	errno = 0; | ||||
| 	ERR_clear_error(); | ||||
| 	n = SSL_write(wsi->tls.ssl, buf, (int)(ssize_t)len); | ||||
| 	if (n > 0) { | ||||
| #if defined(LWS_WITH_SYS_METRICS) | ||||
| 		if (wsi->a.vhost) | ||||
| 			lws_metric_event(wsi->a.vhost->mt_traffic_tx, | ||||
| 					 METRES_GO, (u_mt_t)n); | ||||
| #endif | ||||
| 		return n; | ||||
| 	} | ||||
|  | ||||
| 	m = lws_ssl_get_error(wsi, n); | ||||
| 	if (m != SSL_ERROR_SYSCALL) { | ||||
| 		if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl)) { | ||||
| 			lwsl_notice("%s: want read\n", __func__); | ||||
|  | ||||
| 			return LWS_SSL_CAPABLE_MORE_SERVICE; | ||||
| 		} | ||||
|  | ||||
| 		if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) { | ||||
| 			lws_set_blocking_send(wsi); | ||||
|  | ||||
| 			lwsl_debug("%s: want write\n", __func__); | ||||
|  | ||||
| 			return LWS_SSL_CAPABLE_MORE_SERVICE; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	lwsl_debug("%s failed: %s\n",__func__, ERR_error_string((unsigned int)m, NULL)); | ||||
| 	lws_tls_err_describe_clear(); | ||||
|  | ||||
| 	wsi->socket_is_permanently_unusable = 1; | ||||
|  | ||||
| #if defined(LWS_WITH_SYS_METRICS) | ||||
| 		if (wsi->a.vhost) | ||||
| 			lws_metric_event(wsi->a.vhost->mt_traffic_tx, | ||||
| 					 METRES_NOGO, 0); | ||||
| #endif | ||||
|  | ||||
| 	return LWS_SSL_CAPABLE_ERROR; | ||||
| } | ||||
|  | ||||
| void | ||||
| lws_ssl_info_callback(const SSL *ssl, int where, int ret) | ||||
| { | ||||
| 	struct lws *wsi; | ||||
| 	struct lws_context *context; | ||||
| 	struct lws_ssl_info si; | ||||
| 	int fd; | ||||
|  | ||||
| #ifndef USE_WOLFSSL | ||||
| 	context = (struct lws_context *)SSL_CTX_get_ex_data( | ||||
| 					SSL_get_SSL_CTX(ssl), | ||||
| 					openssl_SSL_CTX_private_data_index); | ||||
| #else | ||||
| 	context = (struct lws_context *)SSL_CTX_get_ex_data( | ||||
| 					SSL_get_SSL_CTX((SSL*) ssl), | ||||
| 					openssl_SSL_CTX_private_data_index); | ||||
| #endif | ||||
| 	if (!context) | ||||
| 		return; | ||||
|  | ||||
| 	fd = SSL_get_fd(ssl); | ||||
| 	if (fd < 0 || (fd - lws_plat_socket_offset()) < 0) | ||||
| 		return; | ||||
|  | ||||
| 	wsi = wsi_from_fd(context, fd); | ||||
| 	if (!wsi) | ||||
| 		return; | ||||
|  | ||||
| 	if (!(where & wsi->a.vhost->tls.ssl_info_event_mask)) | ||||
| 		return; | ||||
|  | ||||
| 	si.where = where; | ||||
| 	si.ret = ret; | ||||
|  | ||||
| 	if (user_callback_handle_rxflow(wsi->a.protocol->callback, | ||||
| 					wsi, LWS_CALLBACK_SSL_INFO, | ||||
| 					wsi->user_space, &si, 0)) | ||||
| 		lws_set_timeout(wsi, PENDING_TIMEOUT_KILLED_BY_SSL_INFO, -1); | ||||
| } | ||||
|  | ||||
|  | ||||
| int | ||||
| lws_ssl_close(struct lws *wsi) | ||||
| { | ||||
| 	lws_sockfd_type n; | ||||
|  | ||||
| 	if (!wsi->tls.ssl) | ||||
| 		return 0; /* not handled */ | ||||
|  | ||||
| #if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK) | ||||
| 	/* kill ssl callbacks, because we will remove the fd from the | ||||
| 	 * table linking it to the wsi | ||||
| 	 */ | ||||
| 	if (wsi->a.vhost->tls.ssl_info_event_mask) | ||||
| 		SSL_set_info_callback(wsi->tls.ssl, NULL); | ||||
| #endif | ||||
|  | ||||
| #if defined(LWS_TLS_SYNTHESIZE_CB) | ||||
| 	lws_sul_cancel(&wsi->tls.sul_cb_synth); | ||||
| 	/* | ||||
| 	 * ... check the session in case it did not live long enough to get | ||||
| 	 * the scheduled callback to sample it | ||||
| 	 */ | ||||
| 	lws_sess_cache_synth_cb(&wsi->tls.sul_cb_synth); | ||||
| #endif | ||||
|  | ||||
| 	n = SSL_get_fd(wsi->tls.ssl); | ||||
| 	if (!wsi->socket_is_permanently_unusable) | ||||
| 		SSL_shutdown(wsi->tls.ssl); | ||||
| 	compatible_close(n); | ||||
| 	SSL_free(wsi->tls.ssl); | ||||
| 	wsi->tls.ssl = NULL; | ||||
|  | ||||
| 	lws_tls_restrict_return(wsi); | ||||
|  | ||||
| 	// lwsl_notice("%s: ssl restr %d, simul %d\n", __func__, | ||||
| 	//		wsi->a.context->simultaneous_ssl_restriction, | ||||
| 	//		wsi->a.context->simultaneous_ssl); | ||||
|  | ||||
| 	return 1; /* handled */ | ||||
| } | ||||
|  | ||||
| void | ||||
| lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost) | ||||
| { | ||||
| 	if (vhost->tls.ssl_ctx) | ||||
| 		SSL_CTX_free(vhost->tls.ssl_ctx); | ||||
|  | ||||
| #if defined(LWS_WITH_CLIENT) | ||||
| 	lws_ssl_destroy_client_ctx(vhost); | ||||
| #endif | ||||
|  | ||||
| #if defined(LWS_WITH_ACME) | ||||
| 	lws_tls_acme_sni_cert_destroy(vhost); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void | ||||
| lws_ssl_context_destroy(struct lws_context *context) | ||||
| { | ||||
| // after 1.1.0 no need | ||||
| #if (OPENSSL_VERSION_NUMBER <  0x10100000) | ||||
| // <= 1.0.1f = old api, 1.0.1g+ = new api | ||||
| #if (OPENSSL_VERSION_NUMBER <= 0x1000106f) || defined(USE_WOLFSSL) | ||||
| 	ERR_remove_state(0); | ||||
| #else | ||||
| #if OPENSSL_VERSION_NUMBER >= 0x1010005f && \ | ||||
|     !defined(LIBRESSL_VERSION_NUMBER) && \ | ||||
|     !defined(OPENSSL_IS_BORINGSSL) | ||||
| 	ERR_remove_thread_state(); | ||||
| #else | ||||
| 	ERR_remove_thread_state(NULL); | ||||
| #endif | ||||
| #endif | ||||
| 	// after 1.1.0 no need | ||||
| #if  (OPENSSL_VERSION_NUMBER >= 0x10002000) && (OPENSSL_VERSION_NUMBER <= 0x10100000) | ||||
| 	SSL_COMP_free_compression_methods(); | ||||
| #endif | ||||
| 	ERR_free_strings(); | ||||
| 	EVP_cleanup(); | ||||
| 	CRYPTO_cleanup_all_ex_data(); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| lws_tls_ctx * | ||||
| lws_tls_ctx_from_wsi(struct lws *wsi) | ||||
| { | ||||
| 	if (!wsi->tls.ssl) | ||||
| 		return NULL; | ||||
|  | ||||
| 	return SSL_get_SSL_CTX(wsi->tls.ssl); | ||||
| } | ||||
|  | ||||
| enum lws_ssl_capable_status | ||||
| __lws_tls_shutdown(struct lws *wsi) | ||||
| { | ||||
| 	int n; | ||||
|  | ||||
| #ifndef WIN32 | ||||
| 	errno = 0; | ||||
| #else | ||||
|   WSASetLastError(0); | ||||
| #endif | ||||
| 	ERR_clear_error(); | ||||
| 	n = SSL_shutdown(wsi->tls.ssl); | ||||
| 	lwsl_debug("SSL_shutdown=%d for fd %d\n", n, wsi->desc.sockfd); | ||||
| 	switch (n) { | ||||
| 	case 1: /* successful completion */ | ||||
| 		n = shutdown(wsi->desc.sockfd, SHUT_WR); | ||||
| 		return LWS_SSL_CAPABLE_DONE; | ||||
|  | ||||
| 	case 0: /* needs a retry */ | ||||
| 		__lws_change_pollfd(wsi, 0, LWS_POLLIN); | ||||
| 		return LWS_SSL_CAPABLE_MORE_SERVICE; | ||||
|  | ||||
| 	default: /* fatal error, or WANT */ | ||||
| 		n = SSL_get_error(wsi->tls.ssl, n); | ||||
| 		if (n != SSL_ERROR_SYSCALL && n != SSL_ERROR_SSL) { | ||||
| 			if (SSL_want_read(wsi->tls.ssl)) { | ||||
| 				lwsl_debug("(wants read)\n"); | ||||
| 				__lws_change_pollfd(wsi, 0, LWS_POLLIN); | ||||
| 				return LWS_SSL_CAPABLE_MORE_SERVICE_READ; | ||||
| 			} | ||||
| 			if (SSL_want_write(wsi->tls.ssl)) { | ||||
| 				lwsl_debug("(wants write)\n"); | ||||
| 				__lws_change_pollfd(wsi, 0, LWS_POLLOUT); | ||||
| 				return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE; | ||||
| 			} | ||||
| 		} | ||||
| 		return LWS_SSL_CAPABLE_ERROR; | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| static int | ||||
| tops_fake_POLLIN_for_buffered_openssl(struct lws_context_per_thread *pt) | ||||
| { | ||||
| 	return lws_tls_fake_POLLIN_for_buffered(pt); | ||||
| } | ||||
|  | ||||
| const struct lws_tls_ops tls_ops_openssl = { | ||||
| 	/* fake_POLLIN_for_buffered */	tops_fake_POLLIN_for_buffered_openssl, | ||||
| }; | ||||
							
								
								
									
										176
									
								
								Kinc/Sources/kinc/libs/tls/openssl/openssl-tls.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								Kinc/Sources/kinc/libs/tls/openssl/openssl-tls.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,176 @@ | ||||
| /* | ||||
|  * libwebsockets - small server side websockets and web server implementation | ||||
|  * | ||||
|  * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com> | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to | ||||
|  * deal in the Software without restriction, including without limitation the | ||||
|  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
|  * sell copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|  * IN THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include "private-lib-core.h" | ||||
| #include "private-lib-tls-openssl.h" | ||||
|  | ||||
| extern int openssl_websocket_private_data_index, | ||||
| 	   openssl_SSL_CTX_private_data_index; | ||||
| #if defined(LWS_WITH_NETWORK) | ||||
| static char openssl_ex_indexes_acquired; | ||||
| #endif | ||||
|  | ||||
| void | ||||
| lws_tls_err_describe_clear(void) | ||||
| { | ||||
| 	char buf[160]; | ||||
| 	unsigned long l; | ||||
|  | ||||
| 	do { | ||||
| 		l = ERR_get_error(); | ||||
| 		if (!l) | ||||
| 			break; | ||||
|  | ||||
| 		ERR_error_string_n( | ||||
| #if defined(LWS_WITH_BORINGSSL) | ||||
| 				(uint32_t) | ||||
| #endif | ||||
| 				l, buf, sizeof(buf)); | ||||
| 		lwsl_info("   openssl error: %s\n", buf); | ||||
| 	} while (l); | ||||
| 	lwsl_info("\n"); | ||||
| } | ||||
|  | ||||
| #if LWS_MAX_SMP != 1 | ||||
|  | ||||
| static pthread_mutex_t *openssl_mutexes = NULL; | ||||
|  | ||||
| static void | ||||
| lws_openssl_lock_callback(int mode, int type, const char *file, int line) | ||||
| { | ||||
| 	(void)file; | ||||
| 	(void)line; | ||||
|  | ||||
| 	if (mode & CRYPTO_LOCK) | ||||
| 		pthread_mutex_lock(&openssl_mutexes[type]); | ||||
| 	else | ||||
| 		pthread_mutex_unlock(&openssl_mutexes[type]); | ||||
| } | ||||
|  | ||||
| static unsigned long | ||||
| lws_openssl_thread_id(void) | ||||
| { | ||||
| #ifdef __PTW32_H | ||||
| 	return (unsigned long)(intptr_t)(pthread_self()).p; | ||||
| #else | ||||
| 	return (unsigned long)pthread_self(); | ||||
| #endif | ||||
| } | ||||
| #endif | ||||
|  | ||||
| int | ||||
| lws_context_init_ssl_library(struct lws_context *cx, | ||||
|                              const struct lws_context_creation_info *info) | ||||
| { | ||||
| #ifdef USE_WOLFSSL | ||||
| #ifdef USE_OLD_CYASSL | ||||
| 	lwsl_cx_info(cx, " Compiled with CyaSSL support"); | ||||
| #else | ||||
| 	lwsl_cx_info(cx, " Compiled with wolfSSL support"); | ||||
| #endif | ||||
| #else | ||||
| #if defined(LWS_WITH_BORINGSSL) | ||||
| 	lwsl_cx_info(cx, " Compiled with BoringSSL support"); | ||||
| #else | ||||
| 	lwsl_cx_info(cx, " Compiled with OpenSSL support"); | ||||
| #endif | ||||
| #endif | ||||
| 	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) { | ||||
| 		if (!info->provided_client_ssl_ctx) | ||||
| 			lwsl_cx_info(cx, " SSL disabled: no " | ||||
| 				"LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* basic openssl init */ | ||||
|  | ||||
| 	lwsl_cx_info(cx, "Doing SSL library init"); | ||||
|  | ||||
| #if OPENSSL_VERSION_NUMBER < 0x10100000L | ||||
| 	SSL_library_init(); | ||||
| 	OpenSSL_add_all_algorithms(); | ||||
| 	SSL_load_error_strings(); | ||||
| #else | ||||
| 	OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); | ||||
| #endif | ||||
| #if defined(LWS_WITH_NETWORK) | ||||
| 	if (!openssl_ex_indexes_acquired) { | ||||
| 		openssl_websocket_private_data_index = | ||||
| 			SSL_get_ex_new_index(0, "lws", NULL, NULL, NULL); | ||||
|  | ||||
| 		openssl_SSL_CTX_private_data_index = | ||||
| 			SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); | ||||
|  | ||||
| 		openssl_ex_indexes_acquired = 1; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| #if LWS_MAX_SMP != 1 | ||||
| 	{ | ||||
| 		int n; | ||||
|  | ||||
| 		openssl_mutexes = (pthread_mutex_t *) | ||||
| 				OPENSSL_malloc((size_t)((unsigned long)CRYPTO_num_locks() * | ||||
| 					       (unsigned long)sizeof(openssl_mutexes[0]))); | ||||
|  | ||||
| 		for (n = 0; n < CRYPTO_num_locks(); n++) | ||||
| 			pthread_mutex_init(&openssl_mutexes[n], NULL); | ||||
|  | ||||
| 		/* | ||||
| 		 * These "functions" disappeared in later OpenSSL which is | ||||
| 		 * already threadsafe. | ||||
| 		 */ | ||||
|  | ||||
| 		(void)lws_openssl_thread_id; | ||||
| 		(void)lws_openssl_lock_callback; | ||||
|  | ||||
| 		CRYPTO_set_id_callback(lws_openssl_thread_id); | ||||
| 		CRYPTO_set_locking_callback(lws_openssl_lock_callback); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| lws_context_deinit_ssl_library(struct lws_context *context) | ||||
| { | ||||
| #if LWS_MAX_SMP != 1 | ||||
| 	int n; | ||||
|  | ||||
| 	if (!lws_check_opt(context->options, | ||||
| 			   LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) | ||||
| 		return; | ||||
|  | ||||
| 	CRYPTO_set_locking_callback(NULL); | ||||
|  | ||||
| 	if (openssl_mutexes) { | ||||
| 		for (n = 0; n < CRYPTO_num_locks(); n++) | ||||
| 			pthread_mutex_destroy(&openssl_mutexes[n]); | ||||
|  | ||||
| 		OPENSSL_free(openssl_mutexes); | ||||
| 		openssl_mutexes = NULL; | ||||
| 	} | ||||
| #endif | ||||
| } | ||||
							
								
								
									
										854
									
								
								Kinc/Sources/kinc/libs/tls/openssl/openssl-x509.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										854
									
								
								Kinc/Sources/kinc/libs/tls/openssl/openssl-x509.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,854 @@ | ||||
| /* | ||||
|  * libwebsockets - small server side websockets and web server implementation | ||||
|  * | ||||
|  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to | ||||
|  * deal in the Software without restriction, including without limitation the | ||||
|  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
|  * sell copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|  * IN THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #define WIN32_LEAN_AND_MEAN | ||||
| #include "private-lib-core.h" | ||||
| #include "private-lib-tls-openssl.h" | ||||
|  | ||||
| #if !defined(LWS_PLAT_OPTEE) | ||||
| static int | ||||
| dec(char c) | ||||
| { | ||||
| 	return c - '0'; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| static time_t | ||||
| lws_tls_openssl_asn1time_to_unix(ASN1_TIME *as) | ||||
| { | ||||
| #if !defined(LWS_PLAT_OPTEE) | ||||
|  | ||||
| 	const char *p = (const char *)as->data; | ||||
| 	struct tm t; | ||||
|  | ||||
| 	/* [YY]YYMMDDHHMMSSZ */ | ||||
|  | ||||
| 	memset(&t, 0, sizeof(t)); | ||||
|  | ||||
| 	if (strlen(p) == 13) { | ||||
| 		t.tm_year = (dec(p[0]) * 10) + dec(p[1]) + 100; | ||||
| 		p += 2; | ||||
| 	} else { | ||||
| 		t.tm_year = (dec(p[0]) * 1000) + (dec(p[1]) * 100) + | ||||
| 			    (dec(p[2]) * 10) + dec(p[3]); | ||||
| 		p += 4; | ||||
| 	} | ||||
| 	t.tm_mon = (dec(p[0]) * 10) + dec(p[1]) - 1; | ||||
| 	p += 2; | ||||
| 	t.tm_mday = (dec(p[0]) * 10) + dec(p[1]) - 1; | ||||
| 	p += 2; | ||||
| 	t.tm_hour = (dec(p[0]) * 10) + dec(p[1]); | ||||
| 	p += 2; | ||||
| 	t.tm_min = (dec(p[0]) * 10) + dec(p[1]); | ||||
| 	p += 2; | ||||
| 	t.tm_sec = (dec(p[0]) * 10) + dec(p[1]); | ||||
| 	t.tm_isdst = 0; | ||||
|  | ||||
| 	return mktime(&t); | ||||
| #else | ||||
| 	return (time_t)-1; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #if defined(USE_WOLFSSL) | ||||
| #define AUTHORITY_KEYID WOLFSSL_AUTHORITY_KEYID | ||||
| #endif | ||||
|  | ||||
| int | ||||
| lws_tls_openssl_cert_info(X509 *x509, enum lws_tls_cert_info type, | ||||
| 			  union lws_tls_cert_info_results *buf, size_t len) | ||||
| { | ||||
| #ifndef USE_WOLFSSL | ||||
| 	const unsigned char *dp; | ||||
| 	ASN1_OCTET_STRING *val; | ||||
| 	AUTHORITY_KEYID *akid; | ||||
| 	X509_EXTENSION *ext; | ||||
| 	int tag, xclass, r = 1; | ||||
| 	long xlen, loc; | ||||
| #endif | ||||
| 	X509_NAME *xn; | ||||
| #if !defined(LWS_PLAT_OPTEE) | ||||
| 	char *p, *p1; | ||||
| 	size_t rl; | ||||
| #endif | ||||
|  | ||||
| 	buf->ns.len = 0; | ||||
|  | ||||
| 	if (!x509) | ||||
| 		return -1; | ||||
| 	if (!len) | ||||
| 		len = sizeof(buf->ns.name); | ||||
|  | ||||
| #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(X509_get_notBefore) | ||||
| #define X509_get_notBefore(x)	X509_getm_notBefore(x) | ||||
| #define X509_get_notAfter(x)	X509_getm_notAfter(x) | ||||
| #endif | ||||
|  | ||||
| 	switch (type) { | ||||
| 	case LWS_TLS_CERT_INFO_VALIDITY_FROM: | ||||
| 		buf->time = lws_tls_openssl_asn1time_to_unix( | ||||
| 					X509_get_notBefore(x509)); | ||||
| 		if (buf->time == (time_t)-1) | ||||
| 			return -1; | ||||
| 		break; | ||||
|  | ||||
| 	case LWS_TLS_CERT_INFO_VALIDITY_TO: | ||||
| 		buf->time = lws_tls_openssl_asn1time_to_unix( | ||||
| 					X509_get_notAfter(x509)); | ||||
| 		if (buf->time == (time_t)-1) | ||||
| 			return -1; | ||||
| 		break; | ||||
|  | ||||
| 	case LWS_TLS_CERT_INFO_COMMON_NAME: | ||||
| #if defined(LWS_PLAT_OPTEE) | ||||
| 		return -1; | ||||
| #else | ||||
| 		xn = X509_get_subject_name(x509); | ||||
| 		if (!xn) | ||||
| 			return -1; | ||||
| 		X509_NAME_oneline(xn, buf->ns.name, (int)len - 2); | ||||
| 		p = strstr(buf->ns.name, "/CN="); | ||||
| 		if (p) { | ||||
| 			p += 4; | ||||
| 			p1 = strchr(p, '/'); | ||||
| 			if (p1) | ||||
| 				rl = lws_ptr_diff_size_t(p1, p); | ||||
| 			else | ||||
| 				rl = strlen(p); | ||||
| 			memmove(buf->ns.name, p, rl); | ||||
| 			buf->ns.name[rl] = '\0'; | ||||
| 		} | ||||
| 		buf->ns.len = (int)strlen(buf->ns.name); | ||||
| 		return 0; | ||||
| #endif | ||||
| 	case LWS_TLS_CERT_INFO_ISSUER_NAME: | ||||
| 		xn = X509_get_issuer_name(x509); | ||||
| 		if (!xn) | ||||
| 			return -1; | ||||
| 		X509_NAME_oneline(xn, buf->ns.name, (int)len - 1); | ||||
| 		buf->ns.len = (int)strlen(buf->ns.name); | ||||
| 		return 0; | ||||
|  | ||||
| 	case LWS_TLS_CERT_INFO_USAGE: | ||||
| #if defined(LWS_HAVE_X509_get_key_usage) | ||||
| 		buf->usage = X509_get_key_usage(x509); | ||||
| 		break; | ||||
| #else | ||||
| 		return -1; | ||||
| #endif | ||||
|  | ||||
| 	case LWS_TLS_CERT_INFO_OPAQUE_PUBLIC_KEY: | ||||
| 	{ | ||||
| #ifndef USE_WOLFSSL | ||||
| 		size_t klen = (unsigned int)i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x509), NULL); | ||||
| 		uint8_t *tmp, *ptmp; | ||||
|  | ||||
| 		if (!klen || klen > len) | ||||
| 			return -1; | ||||
|  | ||||
| 		tmp = (uint8_t *)OPENSSL_malloc(klen); | ||||
| 		if (!tmp) | ||||
| 			return -1; | ||||
|  | ||||
| 		ptmp = tmp; | ||||
| 		if (i2d_X509_PUBKEY( | ||||
| 			      X509_get_X509_PUBKEY(x509), &ptmp) != (int)klen || | ||||
| 		    !ptmp || lws_ptr_diff(ptmp, tmp) != (int)klen) { | ||||
| 			lwsl_info("%s: cert public key extraction failed\n", | ||||
| 				  __func__); | ||||
| 			if (ptmp) | ||||
| 				OPENSSL_free(tmp); | ||||
|  | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		buf->ns.len = (int)klen; | ||||
| 		memcpy(buf->ns.name, tmp, klen); | ||||
| 		OPENSSL_free(tmp); | ||||
| #endif | ||||
| 		return 0; | ||||
| 	} | ||||
| 	case LWS_TLS_CERT_INFO_DER_RAW: | ||||
| 	{ | ||||
| 		int der_len = i2d_X509(x509, NULL); | ||||
| 		uint8_t *tmp = (uint8_t *)buf->ns.name; | ||||
|  | ||||
| 		buf->ns.len = der_len < 0 ? 0 : der_len; | ||||
|  | ||||
| 		if (der_len < 0 || (size_t)der_len > len) | ||||
| 			return -1; | ||||
|  | ||||
| 		der_len = i2d_X509(x509, &tmp); | ||||
| 		if (der_len < 0) | ||||
| 			return -1; | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| #ifndef USE_WOLFSSL | ||||
|  | ||||
| 	case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID: | ||||
| 		loc = X509_get_ext_by_NID(x509, NID_authority_key_identifier, -1); | ||||
| 		if (loc < 0) | ||||
| 			return 1; | ||||
|  | ||||
| 		ext = X509_get_ext(x509, (int)loc); | ||||
| 		if (!ext) | ||||
| 			return 1; | ||||
| #ifndef USE_WOLFSSL | ||||
| 		akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext); | ||||
| #else | ||||
| 		akid = (AUTHORITY_KEYID *)wolfSSL_X509V3_EXT_d2i(ext); | ||||
| #endif | ||||
| 		if (!akid || !akid->keyid) | ||||
| 			return 1; | ||||
| 		val = akid->keyid; | ||||
| 		dp = (const unsigned char *)val->data; | ||||
| 		xlen = val->length; | ||||
|  | ||||
| 		buf->ns.len = (int)xlen; | ||||
| 		if (len < (size_t)buf->ns.len) | ||||
| 			return -1; | ||||
|  | ||||
| 		memcpy(buf->ns.name, dp, (size_t)buf->ns.len); | ||||
|  | ||||
| 		AUTHORITY_KEYID_free(akid); | ||||
| 		break; | ||||
|  | ||||
| 	case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_ISSUER: | ||||
| 		loc = X509_get_ext_by_NID(x509, NID_authority_key_identifier, -1); | ||||
| 		if (loc < 0) | ||||
| 			return 1; | ||||
|  | ||||
| 		ext = X509_get_ext(x509, (int)loc); | ||||
| 		if (!ext) | ||||
| 			return 1; | ||||
|  | ||||
| #ifndef USE_WOLFSSL | ||||
| 		akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext); | ||||
| #else | ||||
| 		akid = (AUTHORITY_KEYID *)wolfSSL_X509V3_EXT_d2i(ext); | ||||
| #endif | ||||
| 		if (!akid || !akid->issuer) | ||||
| 			return 1; | ||||
|  | ||||
| #if defined(LWS_HAVE_OPENSSL_STACK) | ||||
| 		{ | ||||
| 			const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext); | ||||
| 			STACK_OF(CONF_VALUE) *cv; | ||||
| 			int j; | ||||
|  | ||||
| 			cv = i2v_GENERAL_NAMES((X509V3_EXT_METHOD*)method, akid->issuer, NULL); | ||||
| 			if (!cv) | ||||
| 				goto bail_ak; | ||||
|  | ||||
| 		        for (j = 0; j < OPENSSL_sk_num((const OPENSSL_STACK *)&cv); j++) { | ||||
| 		            CONF_VALUE *nval = OPENSSL_sk_value((const OPENSSL_STACK *)&cv, j); | ||||
| 		            size_t ln = (nval->name ? strlen(nval->name) : 0), | ||||
| 		        	   lv = (nval->value ? strlen(nval->value) : 0), | ||||
| 		        	   l = ln + lv; | ||||
|  | ||||
| 		            if (len > l) { | ||||
| 		        	    if (nval->name) | ||||
| 		        		    memcpy(buf->ns.name + buf->ns.len, nval->name, ln); | ||||
| 		        	    if (nval->value) | ||||
| 		        		    memcpy(buf->ns.name + buf->ns.len + ln, nval->value, lv); | ||||
| 		        	    buf->ns.len = (int)((size_t)buf->ns.len + l); | ||||
| 		        	    len -= l; | ||||
| 		        	    buf->ns.name[buf->ns.len] = '\0'; | ||||
|  | ||||
| 		        	    r = 0; | ||||
| 		            } | ||||
| 		        } | ||||
| 		} | ||||
|  | ||||
| bail_ak: | ||||
| #endif | ||||
| 		AUTHORITY_KEYID_free(akid); | ||||
|  | ||||
| 		return r; | ||||
|  | ||||
| 	case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_SERIAL: | ||||
| 		loc = X509_get_ext_by_NID(x509, NID_authority_key_identifier, -1); | ||||
| 		if (loc < 0) | ||||
| 			return 1; | ||||
|  | ||||
| 		ext = X509_get_ext(x509, (int)loc); | ||||
| 		if (!ext) | ||||
| 			return 1; | ||||
| 		akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext); | ||||
| 		if (!akid || !akid->serial) | ||||
| 			return 1; | ||||
|  | ||||
| #if 0 | ||||
| 		// need to handle blobs, and ASN1_INTEGER_get_uint64 not | ||||
| 		// available on older openssl | ||||
| 		{ | ||||
| 			uint64_t res; | ||||
| 			if (ASN1_INTEGER_get_uint64(&res, akid->serial) != 1) | ||||
| 				break; | ||||
| 			buf->ns.len = lws_snprintf(buf->ns.name, len, "%llu", | ||||
| 					(unsigned long long)res); | ||||
| 		} | ||||
| #endif | ||||
| 		break; | ||||
|  | ||||
| 	case LWS_TLS_CERT_INFO_SUBJECT_KEY_ID: | ||||
|  | ||||
| 		loc = X509_get_ext_by_NID(x509, NID_subject_key_identifier, -1); | ||||
| 		if (loc < 0) | ||||
| 			return 1; | ||||
|  | ||||
| 		ext = X509_get_ext(x509, (int)loc); | ||||
| 		if (!ext) | ||||
| 			return 1; | ||||
|  | ||||
| 		val = X509_EXTENSION_get_data(ext); | ||||
| 		if (!val) | ||||
| 			return 1; | ||||
|  | ||||
| #if defined(USE_WOLFSSL) | ||||
| 		return 1; | ||||
| #else | ||||
| 		dp = (const unsigned char *)val->data; | ||||
|  | ||||
| 		if (ASN1_get_object(&dp, &xlen, | ||||
| 				    &tag, &xclass, val->length) & 0x80) | ||||
| 			return -1; | ||||
|  | ||||
| 		if (tag != V_ASN1_OCTET_STRING) { | ||||
| 			lwsl_notice("not octet string %d\n", (int)tag); | ||||
| 			return 1; | ||||
| 		} | ||||
| #endif | ||||
| 		buf->ns.len = (int)xlen; | ||||
| 		if (len < (size_t)buf->ns.len) | ||||
| 			return -1; | ||||
|  | ||||
| 		memcpy(buf->ns.name, dp, (size_t)buf->ns.len); | ||||
| 		break; | ||||
| #endif | ||||
|  | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_x509_info(struct lws_x509_cert *x509, enum lws_tls_cert_info type, | ||||
| 	      union lws_tls_cert_info_results *buf, size_t len) | ||||
| { | ||||
| 	return lws_tls_openssl_cert_info(x509->cert, type, buf, len); | ||||
| } | ||||
|  | ||||
| #if defined(LWS_WITH_NETWORK) | ||||
| int | ||||
| lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type, | ||||
| 		        union lws_tls_cert_info_results *buf, size_t len) | ||||
| { | ||||
| #if defined(LWS_HAVE_SSL_CTX_get0_certificate) | ||||
| 	X509 *x509 = SSL_CTX_get0_certificate(vhost->tls.ssl_ctx); | ||||
|  | ||||
| 	return lws_tls_openssl_cert_info(x509, type, buf, len); | ||||
| #else | ||||
| 	lwsl_notice("openssl is too old to support %s\n", __func__); | ||||
|  | ||||
| 	return -1; | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| int | ||||
| lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type, | ||||
| 		       union lws_tls_cert_info_results *buf, size_t len) | ||||
| { | ||||
| 	int rc = 0; | ||||
| 	X509 *x509; | ||||
|  | ||||
| 	wsi = lws_get_network_wsi(wsi); | ||||
|  | ||||
| 	x509 = SSL_get_peer_certificate(wsi->tls.ssl); | ||||
|  | ||||
| 	if (!x509) { | ||||
| 		lwsl_debug("no peer cert\n"); | ||||
|  | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	switch (type) { | ||||
| 	case LWS_TLS_CERT_INFO_VERIFIED: | ||||
| 		buf->verified = SSL_get_verify_result(wsi->tls.ssl) == | ||||
| 					X509_V_OK; | ||||
| 		break; | ||||
| 	default: | ||||
| 		rc = lws_tls_openssl_cert_info(x509, type, buf, len); | ||||
| 	} | ||||
|  | ||||
| 	X509_free(x509); | ||||
|  | ||||
| 	return rc; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| int | ||||
| lws_x509_create(struct lws_x509_cert **x509) | ||||
| { | ||||
| 	*x509 = lws_malloc(sizeof(**x509), __func__); | ||||
| 	if (*x509) | ||||
| 		(*x509)->cert = NULL; | ||||
|  | ||||
| 	return !(*x509); | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_x509_parse_from_pem(struct lws_x509_cert *x509, const void *pem, size_t len) | ||||
| { | ||||
| 	BIO* bio = BIO_new(BIO_s_mem()); | ||||
|  | ||||
| 	BIO_write(bio, pem, (int)len); | ||||
| 	x509->cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); | ||||
| 	BIO_free(bio); | ||||
| 	if (!x509->cert) { | ||||
| 		lwsl_err("%s: unable to parse PEM cert\n", __func__); | ||||
| 		lws_tls_err_describe_clear(); | ||||
|  | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_x509_verify(struct lws_x509_cert *x509, struct lws_x509_cert *trusted, | ||||
| 		const char *common_name) | ||||
| { | ||||
| 	char c[32], *p; | ||||
| 	int ret; | ||||
|  | ||||
| 	if (common_name) { | ||||
| 		X509_NAME *xn = X509_get_subject_name(x509->cert); | ||||
| 		if (!xn) | ||||
| 			return -1; | ||||
| 		X509_NAME_oneline(xn, c, (int)sizeof(c) - 2); | ||||
| 		p = strstr(c, "/CN="); | ||||
| 		if (p) | ||||
| 			p = p + 4; | ||||
| 		else | ||||
| 			p = c; | ||||
|  | ||||
| 		if (strcmp(p, common_name)) { | ||||
| 			lwsl_err("%s: common name mismatch\n", __func__); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	ret = X509_check_issued(trusted->cert, x509->cert); | ||||
| 	if (ret != X509_V_OK) { | ||||
| 		lwsl_err("%s: unable to verify cert relationship\n", __func__); | ||||
| 		lws_tls_err_describe_clear(); | ||||
|  | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #if defined(LWS_WITH_JOSE) | ||||
| int | ||||
| lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509, | ||||
| 		       const char *curves, int rsa_min_bits) | ||||
| { | ||||
| 	int id, n, ret = -1, count; | ||||
| 	ASN1_OBJECT *obj = NULL; | ||||
| 	const EC_POINT *ecpoint; | ||||
| 	const EC_GROUP *ecgroup; | ||||
| 	EC_KEY *ecpub = NULL; | ||||
| 	X509_PUBKEY *pubkey; | ||||
| 	RSA *rsapub = NULL; | ||||
| 	BIGNUM *mpi[4]; | ||||
| 	EVP_PKEY *pkey; | ||||
|  | ||||
| 	memset(jwk, 0, sizeof(*jwk)); | ||||
|  | ||||
| 	pubkey = X509_get_X509_PUBKEY(x509->cert); | ||||
| 	if (!pubkey) { | ||||
| 		lwsl_err("%s: missing pubkey alg in cert\n", __func__); | ||||
|  | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	if (X509_PUBKEY_get0_param(&obj, NULL, NULL, NULL, pubkey) != 1) { | ||||
| 		lwsl_err("%s: missing pubkey alg in cert\n", __func__); | ||||
|  | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	id = OBJ_obj2nid(obj); | ||||
| 	if (id == NID_undef) { | ||||
| 		lwsl_err("%s: missing pubkey alg in cert\n", __func__); | ||||
|  | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	lwsl_debug("%s: key type %d \"%s\"\n", __func__, id, OBJ_nid2ln(id)); | ||||
|  | ||||
| 	pkey = X509_get_pubkey(x509->cert); | ||||
| 	if (!pkey) { | ||||
| 		lwsl_notice("%s: unable to extract pubkey", __func__); | ||||
|  | ||||
| 		goto bail; | ||||
| 	} | ||||
|  | ||||
| 	switch (id) { | ||||
| 	case NID_X9_62_id_ecPublicKey: | ||||
| 		lwsl_debug("%s: EC key\n", __func__); | ||||
| 		jwk->kty = LWS_GENCRYPTO_KTY_EC; | ||||
|  | ||||
| 		if (!curves) { | ||||
| 			lwsl_err("%s: ec curves not allowed\n", __func__); | ||||
|  | ||||
| 			goto bail1; | ||||
| 		} | ||||
|  | ||||
| 		ecpub = EVP_PKEY_get1_EC_KEY(pkey); | ||||
| 		if (!ecpub) { | ||||
| 			lwsl_notice("%s: missing EC pubkey\n", __func__); | ||||
|  | ||||
| 			goto bail1; | ||||
| 		} | ||||
|  | ||||
| 		ecpoint = EC_KEY_get0_public_key(ecpub); | ||||
| 		if (!ecpoint) { | ||||
| 			lwsl_err("%s: EC_KEY_get0_public_key failed\n", __func__); | ||||
| 			goto bail2; | ||||
| 		} | ||||
|  | ||||
| 		ecgroup = EC_KEY_get0_group(ecpub); | ||||
| 		if (!ecgroup) { | ||||
| 			lwsl_err("%s: EC_KEY_get0_group failed\n", __func__); | ||||
| 			goto bail2; | ||||
| 		} | ||||
|  | ||||
| 		/* validate the curve against ones we allow */ | ||||
|  | ||||
| 		if (lws_genec_confirm_curve_allowed_by_tls_id(curves, | ||||
| 				EC_GROUP_get_curve_name(ecgroup), jwk)) | ||||
| 			/* already logged */ | ||||
| 			goto bail2; | ||||
|  | ||||
| 		mpi[LWS_GENCRYPTO_EC_KEYEL_CRV] = NULL; | ||||
| 		mpi[LWS_GENCRYPTO_EC_KEYEL_X] = BN_new(); /* X */ | ||||
| 		mpi[LWS_GENCRYPTO_EC_KEYEL_D] = NULL; | ||||
| 		mpi[LWS_GENCRYPTO_EC_KEYEL_Y] = BN_new(); /* Y */ | ||||
|  | ||||
| #if defined(LWS_HAVE_EC_POINT_get_affine_coordinates) | ||||
| 		if (EC_POINT_get_affine_coordinates(ecgroup, ecpoint, | ||||
| #else | ||||
| 		if (EC_POINT_get_affine_coordinates_GFp(ecgroup, ecpoint, | ||||
| #endif | ||||
| 						  mpi[LWS_GENCRYPTO_EC_KEYEL_X], | ||||
| 						  mpi[LWS_GENCRYPTO_EC_KEYEL_Y], | ||||
| 							  NULL) != 1) { | ||||
| 			BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_X]); | ||||
| 			BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_Y]); | ||||
| 			lwsl_err("%s: EC_POINT_get_aff failed\n", __func__); | ||||
| 			goto bail2; | ||||
| 		} | ||||
| 		count = LWS_GENCRYPTO_EC_KEYEL_COUNT; | ||||
| 		n = LWS_GENCRYPTO_EC_KEYEL_X; | ||||
| 		break; | ||||
|  | ||||
| 	case NID_rsaEncryption: | ||||
| 		lwsl_debug("%s: rsa key\n", __func__); | ||||
| 		jwk->kty = LWS_GENCRYPTO_KTY_RSA; | ||||
|  | ||||
| 		rsapub = EVP_PKEY_get1_RSA(pkey); | ||||
| 		if (!rsapub) { | ||||
| 			lwsl_notice("%s: missing RSA pubkey\n", __func__); | ||||
|  | ||||
| 			goto bail1; | ||||
| 		} | ||||
|  | ||||
| 		if ((size_t)RSA_size(rsapub) * 8 < (size_t)rsa_min_bits) { | ||||
| 			lwsl_err("%s: key bits %d less than minimum %d\n", | ||||
| 				 __func__, RSA_size(rsapub) * 8, rsa_min_bits); | ||||
|  | ||||
| 			goto bail2; | ||||
| 		} | ||||
|  | ||||
| #if defined(LWS_HAVE_RSA_SET0_KEY) | ||||
| 		/* we don't need d... but the api wants to write it */ | ||||
| 		RSA_get0_key(rsapub, | ||||
| 			    (const BIGNUM **)&mpi[LWS_GENCRYPTO_RSA_KEYEL_N], | ||||
| 			    (const BIGNUM **)&mpi[LWS_GENCRYPTO_RSA_KEYEL_E], | ||||
| 			    (const BIGNUM **)&mpi[LWS_GENCRYPTO_RSA_KEYEL_D]); | ||||
| #else | ||||
| 		mpi[LWS_GENCRYPTO_RSA_KEYEL_E] = rsapub->e; | ||||
| 		mpi[LWS_GENCRYPTO_RSA_KEYEL_N] = rsapub->n; | ||||
| 		mpi[LWS_GENCRYPTO_RSA_KEYEL_D] = NULL; | ||||
| #endif | ||||
| 		count = LWS_GENCRYPTO_RSA_KEYEL_D; | ||||
| 		n = LWS_GENCRYPTO_RSA_KEYEL_E; | ||||
| 		break; | ||||
| 	default: | ||||
| 		lwsl_err("%s: unknown NID\n", __func__); | ||||
| 		goto bail2; | ||||
| 	} | ||||
|  | ||||
| 	for (; n < count; n++) { | ||||
| 		if (!mpi[n]) | ||||
| 			continue; | ||||
| 		jwk->e[n].len = (unsigned int)BN_num_bytes(mpi[n]); | ||||
| 		jwk->e[n].buf = lws_malloc(jwk->e[n].len, "certkeyimp"); | ||||
| 		if (!jwk->e[n].buf) { | ||||
| 			if (id == NID_X9_62_id_ecPublicKey) { | ||||
| 				BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_X]); | ||||
| 				BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_Y]); | ||||
| 			} | ||||
| 			goto bail2; | ||||
| 		} | ||||
| 		BN_bn2bin(mpi[n], jwk->e[n].buf); | ||||
| 	} | ||||
|  | ||||
| 	if (id == NID_X9_62_id_ecPublicKey) { | ||||
| 		BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_X]); | ||||
| 		BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_Y]); | ||||
| 	} | ||||
|  | ||||
| 	ret = 0; | ||||
|  | ||||
| bail2: | ||||
| 	if (id == NID_X9_62_id_ecPublicKey) | ||||
| 		EC_KEY_free(ecpub); | ||||
| 	else | ||||
| 		RSA_free(rsapub); | ||||
|  | ||||
| bail1: | ||||
| 	EVP_PKEY_free(pkey); | ||||
| bail: | ||||
| 	/* jwk destroy will clean any partial state */ | ||||
| 	if (ret) | ||||
| 		lws_jwk_destroy(jwk); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static int | ||||
| lws_x509_jwk_privkey_pem_pp_cb(char *buf, int size, int rwflag, void *u) | ||||
| { | ||||
| 	const char *pp = (const char *)u; | ||||
| 	size_t n = strlen(pp); | ||||
|  | ||||
| 	if ((int)n > size - 1) | ||||
| 		return -1; | ||||
|  | ||||
| 	memcpy(buf, pp, n + 1); | ||||
|  | ||||
| 	return (int)n; | ||||
| } | ||||
|  | ||||
| int | ||||
| lws_x509_jwk_privkey_pem(struct lws_context *cx, struct lws_jwk *jwk, | ||||
| 			 void *pem, size_t len, const char *passphrase) | ||||
| { | ||||
| 	BIO* bio = BIO_new(BIO_s_mem()); | ||||
| 	BIGNUM *mpi, *dummy[6]; | ||||
| 	EVP_PKEY *pkey = NULL; | ||||
| 	EC_KEY *ecpriv = NULL; | ||||
| 	RSA *rsapriv = NULL; | ||||
| 	const BIGNUM *cmpi; | ||||
| 	int n, m, ret = -1; | ||||
|  | ||||
| 	BIO_write(bio, pem, (int)len); | ||||
| 	PEM_read_bio_PrivateKey(bio, &pkey, lws_x509_jwk_privkey_pem_pp_cb, | ||||
| 				(void *)passphrase); | ||||
| 	BIO_free(bio); | ||||
| 	lws_explicit_bzero((void *)pem, len); | ||||
| 	if (!pkey) { | ||||
| 		lwsl_err("%s: unable to parse PEM privkey\n", __func__); | ||||
| 		lws_tls_err_describe_clear(); | ||||
|  | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* confirm the key type matches the existing jwk situation */ | ||||
|  | ||||
| 	switch (jwk->kty) { | ||||
| 	case LWS_GENCRYPTO_KTY_EC: | ||||
| 		if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) { | ||||
| 			lwsl_err("%s: jwk is EC but privkey isn't\n", __func__); | ||||
|  | ||||
| 			goto bail; | ||||
| 		} | ||||
| 		ecpriv = EVP_PKEY_get1_EC_KEY(pkey); | ||||
| 		if (!ecpriv) { | ||||
| 			lwsl_notice("%s: missing EC key\n", __func__); | ||||
|  | ||||
| 			goto bail; | ||||
| 		} | ||||
|  | ||||
| 		cmpi = EC_KEY_get0_private_key(ecpriv); | ||||
|  | ||||
| 		/* quick size check first */ | ||||
|  | ||||
| 		n = BN_num_bytes(cmpi); | ||||
| 		if (jwk->e[LWS_GENCRYPTO_EC_KEYEL_Y].len != (uint32_t)n) { | ||||
| 			lwsl_err("%s: jwk key size doesn't match\n", __func__); | ||||
|  | ||||
| 			goto bail1; | ||||
| 		} | ||||
|  | ||||
| 		/* TODO.. check public curve / group + point */ | ||||
|  | ||||
| 		jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].len = (unsigned int)n; | ||||
| 		jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf = lws_malloc((unsigned int)n, "ec"); | ||||
| 		if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf) | ||||
| 			goto bail1; | ||||
|  | ||||
| 		m = BN_bn2binpad(cmpi, jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf, | ||||
| 				      (int32_t)jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].len); | ||||
| 		if ((unsigned int)m != (unsigned int)BN_num_bytes(cmpi)) | ||||
| 			goto bail1; | ||||
|  | ||||
| 		break; | ||||
|  | ||||
| 	case LWS_GENCRYPTO_KTY_RSA: | ||||
| 		if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_RSA) { | ||||
| 			lwsl_err("%s: RSA jwk, non-RSA privkey\n", __func__); | ||||
|  | ||||
| 			goto bail; | ||||
| 		} | ||||
| 		rsapriv = EVP_PKEY_get1_RSA(pkey); | ||||
| 		if (!rsapriv) { | ||||
| 			lwsl_notice("%s: missing RSA key\n", __func__); | ||||
|  | ||||
| 			goto bail; | ||||
| 		} | ||||
|  | ||||
| #if defined(LWS_HAVE_RSA_SET0_KEY) && !defined(USE_WOLFSSL) | ||||
| 		RSA_get0_key(rsapriv, (const BIGNUM **)&dummy[0], /* n */ | ||||
| 				      (const BIGNUM **)&dummy[1], /* e */ | ||||
| 				      (const BIGNUM **)&mpi);	  /* d */ | ||||
| 		RSA_get0_factors(rsapriv, (const BIGNUM **)&dummy[4],  /* p */ | ||||
| 					  (const BIGNUM **)&dummy[5]); /* q */ | ||||
| #else | ||||
| 		dummy[0] = rsapriv->n; | ||||
| 		dummy[1] = rsapriv->e; | ||||
| 		dummy[4] = rsapriv->p; | ||||
| 		dummy[5] = rsapriv->q; | ||||
| 		mpi = rsapriv->d; | ||||
| #endif | ||||
|  | ||||
| 		/* quick size check first */ | ||||
|  | ||||
| 		n = BN_num_bytes(mpi); | ||||
| 		if (jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len != (uint32_t)n) { | ||||
| 			lwsl_err("%s: jwk key size doesn't match\n", __func__); | ||||
|  | ||||
| 			goto bail1; | ||||
| 		} | ||||
|  | ||||
| 		/* then check that n & e match what we got from the cert */ | ||||
|  | ||||
| 		dummy[2] = BN_bin2bn(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].buf, | ||||
| 				     (int32_t)jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len, | ||||
| 				     NULL); | ||||
| 		dummy[3] = BN_bin2bn(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].buf, | ||||
| 				     (int32_t)jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].len, | ||||
| 				     NULL); | ||||
|  | ||||
| 		m = BN_cmp(dummy[2], dummy[0]) | BN_cmp(dummy[3], dummy[1]); | ||||
| 		BN_clear_free(dummy[2]); | ||||
| 		BN_clear_free(dummy[3]); | ||||
| 		if (m) { | ||||
| 			lwsl_err("%s: privkey doesn't match jwk pubkey\n", | ||||
| 				 __func__); | ||||
|  | ||||
| 			goto bail1; | ||||
| 		} | ||||
|  | ||||
| 		/* accept d from the PEM privkey into the JWK */ | ||||
|  | ||||
| 		jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].len = (unsigned int)n; | ||||
| 		jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf = lws_malloc((unsigned int)n, "privjk"); | ||||
| 		if (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf) | ||||
| 			goto bail1; | ||||
|  | ||||
| 		BN_bn2bin(mpi, jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf); | ||||
|  | ||||
| 		/* accept p and q from the PEM privkey into the JWK */ | ||||
|  | ||||
| 		jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].len = (unsigned int)BN_num_bytes(dummy[4]); | ||||
| 		jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf = lws_malloc((unsigned int)n, "privjk"); | ||||
| 		if (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf) { | ||||
| 			lws_free_set_NULL(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf); | ||||
| 			goto bail1; | ||||
| 		} | ||||
| 		BN_bn2bin(dummy[4], jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf); | ||||
|  | ||||
| 		jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].len = (unsigned int)BN_num_bytes(dummy[5]); | ||||
| 		jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf = lws_malloc((unsigned int)n, "privjk"); | ||||
| 		if (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf) { | ||||
| 			lws_free_set_NULL(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf); | ||||
| 			lws_free_set_NULL(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf); | ||||
| 			goto bail1; | ||||
| 		} | ||||
| 		BN_bn2bin(dummy[5], jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf); | ||||
| 		break; | ||||
| 	default: | ||||
| 		lwsl_err("%s: JWK has unknown kty %d\n", __func__, jwk->kty); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	ret = 0; | ||||
|  | ||||
| bail1: | ||||
| 	if (jwk->kty == LWS_GENCRYPTO_KTY_EC) | ||||
| 		EC_KEY_free(ecpriv); | ||||
| 	else | ||||
| 		RSA_free(rsapriv); | ||||
|  | ||||
| bail: | ||||
| 	EVP_PKEY_free(pkey); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void | ||||
| lws_x509_destroy(struct lws_x509_cert **x509) | ||||
| { | ||||
| 	if (!*x509) | ||||
| 		return; | ||||
|  | ||||
| 	if ((*x509)->cert) { | ||||
| 		X509_free((*x509)->cert); | ||||
| 		(*x509)->cert = NULL; | ||||
| 	} | ||||
|  | ||||
| 	lws_free_set_NULL(*x509); | ||||
| } | ||||
							
								
								
									
										62
									
								
								Kinc/Sources/kinc/libs/tls/openssl/private-lib-tls-openssl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								Kinc/Sources/kinc/libs/tls/openssl/private-lib-tls-openssl.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | ||||
|  /* | ||||
|  * libwebsockets - small server side websockets and web server implementation | ||||
|  * | ||||
|  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to | ||||
|  * deal in the Software without restriction, including without limitation the | ||||
|  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
|  * sell copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|  * IN THE SOFTWARE. | ||||
|  * | ||||
|  *  gencrypto openssl-specific helper declarations | ||||
|  */ | ||||
|  | ||||
| #if !defined(__LWS_PRIVATE_LIB_TLS_OPENSSL_H__) | ||||
| #define __LWS_PRIVATE_LIB_TLS_OPENSSL_H__ | ||||
|  | ||||
| /* | ||||
|  * one of these per different client context | ||||
|  * cc_owner is in lws_context.lws_context_tls | ||||
|  */ | ||||
|  | ||||
| struct lws_tls_client_reuse { | ||||
| 	lws_tls_ctx *ssl_client_ctx; | ||||
| 	uint8_t hash[32]; | ||||
| 	struct lws_dll2 cc_list; | ||||
| 	int refcount; | ||||
| 	int index; | ||||
| }; | ||||
|  | ||||
| typedef int (*next_proto_cb)(SSL *, const unsigned char **out, | ||||
|                              unsigned char *outlen, const unsigned char *in, | ||||
|                              unsigned int inlen, void *arg); | ||||
|  | ||||
| struct lws_x509_cert { | ||||
| 	X509 *cert; /* X509 is opaque, this has to be a pointer */ | ||||
| }; | ||||
|  | ||||
| int | ||||
| lws_gencrypto_openssl_hash_to_NID(enum lws_genhash_types hash_type); | ||||
|  | ||||
| const EVP_MD * | ||||
| lws_gencrypto_openssl_hash_to_EVP_MD(enum lws_genhash_types hash_type); | ||||
|  | ||||
| #if !defined(LWS_HAVE_BN_bn2binpad) | ||||
| int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen); | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
|  | ||||
		Reference in New Issue
	
	Block a user