HTTP-сервер в Indy 9 представлен компонентом TIdHTTPServer. Чтобы включить использование SSL (HTTPS), нужно у объекта TIdHTTPServer свойство IOHandler связать с объектом типа TIdServerIOHandlerSSL, в котором в поле CertFile прописать путь к файлу сертификата, а в KeyFile - путь к файлу с приватным ключом.
Файл сертификата имеет примерно такое содержимое:
Файл с приватным ключом выглядит примерно так:
Но что делать, если необходимо, чтобы сертификат и ключ были “вшиты” в приложение? Я использую следующую технику - после загрузки и инициализации библиотеки ssleay32.dll подменяю указатели на функции IdSslCtxUseCertificateFile и IdSslCtxUsePrivateKeyFile (они объявлены в IdSSLOpenSSLHeaders) на мои реализации этих функций, которые читают сертификат и ключ не из файлов, а из памяти.
unit uOpenSSL;interface uses Windows, SysUtils, IdSSLOpenSSL, IdSSLOpenSSLHeaders;function MySslCtxUsePrivateKeyFile (ctx: PSSL_CTX; const _file: PChar; _type: Integer) : Integer cdecl ;function MySslCtxUseCertificateFile (ctx: PSSL_CTX; const _file: PChar; _type: Integer) : Integer cdecl ;type PBIO = Pointer; PPBIO =^PBIO; PBIO_METHOD = Pointer; PRSA = Pointer; var MySslCtxUsePrivateKey : function (ctx: PSSL_CTX; pkey: PEVP_PKEY) : Integer cdecl = nil ; MySslCtxUseCertificate : function (ctx: PSSL_CTX; x: PX509) : Integer cdecl = nil ; EVP_PKEY_new : function () : PEVP_PKEY cdecl = nil ; EVP_PKEY_free : procedure (pkey: PEVP_PKEY) cdecl = nil ; EVP_PKEY_set1_RSA : function (pkey: PEVP_PKEY; key: PRSA) : Integer cdecl = nil ; BIO_s_mem : function () : PBIO_METHOD cdecl = nil ; BIO_new : function (t: PBIO_METHOD) : PBIO cdecl = nil ; BIO_free : function (a: PBIO) : Integer cdecl = nil ; BIO_puts : function (bp: PBIO; buf: PChar) : Integer cdecl = nil ; RSA_new: function () : pRSA; cdecl = nil ; RSA_free: procedure (r: pRSA) ; cdecl = nil ; RSA_public_encrypt: function (flen: integer; from: PChar; _to: PChar; rsa: pRSA; padding: integer) : integer; cdecl = nil ; RSA_public_decrypt: function (flen: integer; from: PChar; _to: PChar; rsa: pRSA; padding: integer) : integer; cdecl ; d2i_RSAPrivateKey : function (a: Pointer; pp: Pointer; length: Integer) : PRSA cdecl = nil ; PEM_ASN1_read_bio : function (d2: Pointer; name : PChar; bp: PBIO; x: Pointer; cb: Pointer; u: Pointer) : PChar cdecl = nil ; PEM_read_bio_X509 : function (bp: PBIO; x: Pointer; cb: Pointer; u: Pointer) : PX509 cdecl = nil ; PEM_read_bio_RSAPublicKey: function (bp: pBIO; x: pRSA; cb: Pointer; u: pointer) : pRSA; cdecl = nil ;implementation uses SyncObjs;const SSL_DLL_name = 'ssleay32.dll' ; SSLCLIB_DLL_name = 'libeay32.dll' ; var hIdSSL : Integer = 0 ; hIdCrypto : Integer = 0 ; function LoadFunction (FceName:String ) : Pointer;begin FceName := FceName+#0 ; Result := GetProcAddress(hIdSSL, @FceName[1 ]); end ;function LoadFunctionCLib (FceName:String ) : Pointer;begin FceName := FceName+#0 ; Result := GetProcAddress(hIdCrypto, @FceName[1 ]); end ;const fn_SSL_CTX_use_RSAPrivateKey = 'SSL_CTX_use_RSAPrivateKey' ; fn_SSL_CTX_use_PrivateKey = 'SSL_CTX_use_PrivateKey' ; fn_SSL_CTX_use_certificate = 'SSL_CTX_use_certificate' ; fn_EVP_PKEY_new = 'EVP_PKEY_new' ; fn_EVP_PKEY_free = 'EVP_PKEY_free' ; fn_EVP_PKEY_set1_RSA = 'EVP_PKEY_set1_RSA' ; fn_BIO_s_mem = 'BIO_s_mem' ; fn_BIO_new = 'BIO_new' ; fn_BIO_free = 'BIO_free' ; fn_BIO_puts = 'BIO_puts' ; fn_RSA_new = 'RSA_new' ; fn_RSA_free = 'RSA_free' ; fn_RSA_public_encrypt = 'RSA_public_encrypt' ; fn_RSA_public_decrypt = 'RSA_public_decrypt' ; fn_d2i_RSAPrivateKey = 'd2i_RSAPrivateKey' ; fn_PEM_ASN1_read_bio = 'PEM_ASN1_read_bio' ; fn_PEM_read_bio_X509 = 'PEM_read_bio_X509' ; fn_PEM_read_bio_RSAPublicKey = 'PEM_read_bio_RSAPublicKey' ; var c_PrivateKeyPassword: PChar = 'put the password of your private key here' ; c_PrivateKey: PChar = 'put your private key here' ; c_Certificate: PChar = 'put your certificate here' ; LockPassCB: TCriticalSection; function MyPasswordCallback (buf:PChar; size:Integer; rwflag:Integer; userdata: Pointer) : Integer; cdecl ;begin LockPassCB.Acquire; try size := StrLen(c_PrivateKeyPassword); StrCopy(buf, c_PrivateKeyPassword); Result := size; finally LockPassCB.Release; end ; end ;function MySslCtxUsePrivateKeyFile (ctx: PSSL_CTX; const _file: PChar; _type: Integer) : Integer cdecl ;var pk: PEVP_PKEY; rsakey: PRSA; pMemBIO: PBIO; begin pk := EVP_PKEY_new(); try pMemBIO := BIO_new(BIO_s_mem()); try BIO_puts(pMemBIO, c_PrivateKey); rsakey := PEM_ASN1_read_bio( @d2i_RSAPrivateKey, OPENSSL_PEM_STRING_RSA, pMemBIO, nil , @MyPasswordCallback, nil ); finally BIO_free(pMemBIO); end ; EVP_PKEY_set1_RSA(pk, rsakey); Result := MySslCtxUsePrivateKey(ctx, pk); finally EVP_PKEY_free(pk); end ; end ;function MySslCtxUseCertificateFile (ctx: PSSL_CTX; const _file: PChar; _type: Integer) : Integer cdecl ;var pCert: PX509; pMemBIO: PBIO; begin pMemBIO := BIO_new(BIO_s_mem()); try BIO_puts(pMemBIO, c_Certificate); pCert := PEM_read_bio_X509(pMemBIO, nil , @MyPasswordCallback, nil ); finally BIO_free(pMemBIO); end ; Result := MySslCtxUseCertificate(ctx, pCert); end ;var ctx: TIdSSLContext; initialization LockPassCB := TCriticalSection.Create; ctx := TIdSSLContext.Create; try hIdCrypto := GetModuleHandle(SSLCLIB_DLL_name); hIdSSL := GetModuleHandle(SSL_DLL_name); @MySslCtxUsePrivateKey := LoadFunction(fn_SSL_CTX_use_PrivateKey); @MySslCtxUseCertificate := LoadFunction(fn_SSL_CTX_use_certificate); @EVP_PKEY_new := LoadFunctionCLib(fn_EVP_PKEY_new); @EVP_PKEY_free := LoadFunctionCLib(fn_EVP_PKEY_free); @EVP_PKEY_set1_RSA := LoadFunctionCLib(fn_EVP_PKEY_set1_RSA); @BIO_s_mem := LoadFunctionCLib(fn_BIO_s_mem); @BIO_new := LoadFunctionCLib(fn_BIO_new); @BIO_free := LoadFunctionCLib(fn_BIO_free); @BIO_puts := LoadFunctionCLib(fn_BIO_puts); @RSA_new := LoadFunctionCLib(fn_RSA_new); @RSA_free := LoadFunctionCLib(fn_RSA_free); @RSA_public_encrypt := LoadFunctionCLib(fn_RSA_public_encrypt); @RSA_public_decrypt := LoadFunctionCLib(fn_RSA_public_decrypt); @d2i_RSAPrivateKey := LoadFunctionCLib(fn_d2i_RSAPrivateKey); @PEM_ASN1_read_bio := LoadFunctionCLib(fn_PEM_ASN1_read_bio); @PEM_read_bio_X509 := LoadFunctionCLib(fn_PEM_read_bio_X509); @PEM_read_bio_RSAPublicKey := LoadFunctionCLib(fn_PEM_read_bio_RSAPublicKey); IdSslCtxUsePrivateKeyFile := MySslCtxUsePrivateKeyFile; IdSslCtxUseCertificateFile := MySslCtxUseCertificateFile; finally ctx.Free; end ; finalization LockPassCB.Free; end .
=== Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru