Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Решение ошибки "Could not load certificate" при использовании TIdHTTP и SSL-сертификатов в Delphi

Delphi , Синтаксис , Шифрование

 

При работе с HTTPS-запросами в Delphi с использованием компонента TIdHTTP и SSL-сертификатов разработчики часто сталкиваются с ошибкой:

EIdOSSLLoadingCertError with message 'Could not load certificate. error:0906D06C:PEM routines:PEM_read_bio:no start line'

Эта ошибка возникает, когда компонент TIdSSLIOHandlerSocketOpenSSL не может правильно загрузить SSL-сертификат или приватный ключ. Рассмотрим причины и решения этой проблемы.

Основные причины ошибки

  1. Неправильное форматирование файлов сертификата и ключа
  2. Наличие BOM (Byte Order Mark) в UTF-8 файлах
  3. Проблемы с путями к файлам
  4. Некорректное содержимое сертификата или ключа

Решение проблемы

1. Удаление BOM из файлов сертификата

Основная проблема в предоставленном коде - использование TEncoding.UTF8 при сохранении файлов сертификата и ключа. Это добавляет BOM в начало файла, что может мешать OpenSSL правильно прочитать файл.

Исправленная версия функции LoadCertificate:

function TAPI.LoadCertificate: TIdSSLIOHandlerSocketOpenSSL;
var
  fileCrt, fileKey: TStringList;
  var_path_system: string;
begin
  if Assigned(SSLIOHandler) then
    SSLIOHandler := nil;

  SSLIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);

  fileCrt := TStringList.Create;
  try
    fileKey := TStringList.Create;
    try
      fileCrt.Text := const_cert;
      fileKey.Text := const_private_key;

      var_path_system := ExtractFilePath(Application.ExeName);

      // Отключаем BOM для файлов
      fileCrt.WriteBOM := False;
      fileKey.WriteBOM := False;

      fileCrt.SaveToFile(var_path_system + 'Certificate.crt', TEncoding.ASCII);
      fileKey.SaveToFile(var_path_system + 'PrivateKeyFile.key', TEncoding.ASCII);

      SSLIOHandler.Port := 443;
      SSLIOHandler.DefaultPort := 443;

      SSLIOHandler.SSLOptions.CertFile := var_path_system + 'Certificate.crt';
      SSLIOHandler.SSLOptions.KeyFile := var_path_system + 'PrivateKeyFile.key';

      SSLIOHandler.SSLOptions.Method := sslvTLSv1_2;
      SSLIOHandler.SSLOptions.SSLVersions := [sslvTLSv1_2];
      SSLIOHandler.SSLOptions.Mode := sslmClient;
      SSLIOHandler.SSLOptions.VerifyMode := [];
      SSLIOHandler.SSLOptions.VerifyDepth := 0;
      SSLIOHandler.Host := 'place.holder.com';
    finally
      fileKey.Free;
    end;
  finally
    fileCrt.Free;
  end;

  Result := SSLIOHandler;
end;

2. Альтернативный подход: загрузка сертификата без сохранения в файл

Если возможно, лучше вообще избегать сохранения сертификатов в файлы. Вот альтернативный подход с использованием TIdServerIOHandlerSSLOpenSSL:

function TAPI.LoadCertificateInMemory: TIdSSLIOHandlerSocketOpenSSL;
var
  SSLContext: TIdSSLContext;
begin
  if Assigned(SSLIOHandler) then
    SSLIOHandler := nil;

  SSLIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);

  SSLContext := SSLIOHandler.SSLOptions.CreateSSLContext(sslmClient);
  try
    SSLContext.Certificate.LoadFromString(const_cert);
    SSLContext.Key.LoadFromString(const_private_key);

    SSLIOHandler.SSLOptions.Method := sslvTLSv1_2;
    SSLIOHandler.SSLOptions.SSLVersions := [sslvTLSv1_2];
    SSLIOHandler.SSLOptions.Mode := sslmClient;
    SSLIOHandler.SSLOptions.VerifyMode := [];
    SSLIOHandler.SSLOptions.VerifyDepth := 0;
    SSLIOHandler.Host := 'place.holder.com';
  except
    SSLContext.Free;
    raise;
  end;

  Result := SSLIOHandler;
end;

3. Проверка формата сертификата и ключа

Убедитесь, что ваши константы const_cert и const_private_key содержат корректные данные. Проверьте:

  1. Наличие правильных заголовков -----BEGIN CERTIFICATE----- и -----END CERTIFICATE-----
  2. Отсутствие лишних символов в начале или конце строк
  3. Корректность base64-кодирования содержимого

Пример правильного формата:

const
  const_cert = 
    '-----BEGIN CERTIFICATE-----' + sLineBreak +
    'MIIDXTCCAkWgAwIBAgIJAN...' + sLineBreak + // пример сокращен
    '-----END CERTIFICATE-----';

  const_private_key = 
    '-----BEGIN PRIVATE KEY-----' + sLineBreak +
    'MIIEvQIBADANBgkqhk...' + sLineBreak + // пример сокращен
    '-----END PRIVATE KEY-----';

Оптимизация функции GetToken

Вот улучшенная версия функции GetToken с учетом замечаний:

function TAPI.GetToken: string;
var
  IdHTTP: TIdHTTP;
  Params: TStringList;
  ResponseStream: TStringStream;
begin
  IdHTTP := TIdHTTP.Create(nil);
  try
    IdHTTP.IOHandler := LoadCertificate; // или LoadCertificateInMemory

    ResponseStream := TStringStream.Create('', TEncoding.UTF8);
    try
      Params := TStringList.Create;
      try
        Params.Add('client_id=' + FAAuthorization);
        Params.Add('client_secret=' + FAAuthorizationSecret);
        Params.Add('grant_type=client_credentials');

        IdHTTP.Request.ContentType := 'application/x-www-form-urlencoded';

        try
          IdHTTP.Post(URLBasic, Params, ResponseStream);
          Result := ResponseStream.DataString;
        except
          on E: EIdHTTPProtocolException do
            LogHttpClientError(E, IdHTTP.ResponseCode, False);
          on E: Exception do
            raise;
        end;
      finally
        Params.Free;
      end;
    finally
      ResponseStream.Free;
    end;
  finally
    IdHTTP.Free;
  end;
end;

Дополнительные рекомендации

  1. Проверка версии OpenSSL: Убедитесь, что используете актуальную версию библиотек OpenSSL, совместимых с вашей версией Delphi.

  2. Проверка сертификата вручную: Попробуйте открыть сохраненные файлы сертификата и ключа в текстовом редакторе и убедиться, что они выглядят корректно.

  3. Логирование: Добавьте логирование перед вызовом Post, чтобы записывать точные параметры запроса и содержимое файлов сертификатов.

  4. Альтернативные методы: Если проблема сохраняется, попробуйте использовать другие компоненты для HTTPS-запросов, например TNetHTTPClient из стандартной библиотеки.

Следуя этим рекомендациям, вы сможете решить проблему с загрузкой SSL-сертификатов в Delphi и успешно выполнять HTTPS-запросы с аутентификацией по клиентскому сертификату.

Создано по материалам из источника по ссылке.

Решение ошибки "Could not load certificate" при работе с TIdHTTP и SSL-сертификатами в Delphi, включая проверку формата файлов, удаление BOM и альтернативные методы загрузки.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Шифрование ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-07-14 05:10:53/0.0036790370941162/0