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

Ошибка загрузки сертификата SSL в Delphi: "No start line" при использовании TIdHTTP и TIdSSLIOHandlerSocketOpenSSL

Delphi , Синтаксис , Ошибки и Исключения

 

Введение

При работе с HTTPS-запросами в Delphi с использованием компонентов Indy (TIdHTTP и TIdSSLIOHandlerSocketOpenSSL) разработчики часто сталкиваются с ошибками загрузки SSL-сертификатов. Одна из распространенных проблем - ошибка EIdOSSLLoadingCertError с сообщением "Could not load certificate. error:0906D06C:PEM routines:PEM_read_bio:no start line".

Причины ошибки

Основные причины возникновения ошибки "no start line":

  1. Неправильное форматирование PEM-файлов: OpenSSL ожидает строго определенный формат для сертификатов и приватных ключей.

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

  3. Проблемы с путями к файлам: Неправильно указанные пути или отсутствие прав доступа к файлам.

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

1. Устранение проблемы с BOM

Основное решение - отключить запись BOM при сохранении PEM-файлов:

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;

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

      var_path_system := ExtractFilePath(Application.ExeName);

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

      // Настройка SSLIOHandler
      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. Альтернативное решение: использование TMemoryStream

Вместо сохранения во временные файлы можно использовать TMemoryStream для загрузки сертификата напрямую:

function TAPI.LoadCertificateFromMemory: TIdSSLIOHandlerSocketOpenSSL;
var
  CertStream, KeyStream: TMemoryStream;
begin
  if Assigned(SSLIOHandler) then
    SSLIOHandler := nil;

  SSLIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);

  CertStream := TMemoryStream.Create;
  try
    KeyStream := TMemoryStream.Create;
    try
      // Преобразуем строки в потоки
      StringToStream(const_cert, CertStream);
      StringToStream(const_private_key, KeyStream);

      // Устанавливаем позицию в начало потоков
      CertStream.Position := 0;
      KeyStream.Position := 0;

      // Загружаем сертификат и ключ из потоков
      SSLIOHandler.SSLOptions.CertStream := CertStream;
      SSLIOHandler.SSLOptions.KeyStream := KeyStream;

      // Остальные настройки
      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
      KeyStream.Free;
      raise;
    end;
  except
    CertStream.Free;
    raise;
  end;

  Result := SSLIOHandler;
end;

procedure StringToStream(const AString: string; AStream: TStream);
var
  Bytes: TBytes;
begin
  Bytes := TEncoding.UTF8.GetBytes(AString);
  AStream.WriteBuffer(Bytes[0], Length(Bytes));
end;

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

Убедитесь, что ваши сертификаты имеют правильный формат:

function ValidatePEMFormat(const APEMString: string): Boolean;
begin
  Result := (Pos('-----BEGIN CERTIFICATE-----', APEMString) > 0) and 
            (Pos('-----END CERTIFICATE-----', APEMString) > 0) and
            (Pos('-----BEGIN PRIVATE KEY-----', APEMString) > 0) and 
            (Pos('-----END PRIVATE KEY-----', APEMString) > 0);
end;

Оптимизация кода для HTTP-запросов

Вот улучшенная версия метода GetToken:

function TAPI.GetToken: string;
var
  IdHTTP: TIdHTTP;
  Params: TStringList;
  ResponseStream: TStringStream;
begin
  IdHTTP := TIdHTTP.Create(nil);
  try
    // Настраиваем обработчик SSL
    IdHTTP.IOHandler := LoadCertificate;

    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;

Заключение

Ошибка "no start line" при работе с SSL-сертификатами в Delphi чаще всего связана с проблемами форматирования PEM-файлов. Основные решения включают:

  1. Отключение BOM при сохранении файлов
  2. Использование потоков памяти вместо временных файлов
  3. Тщательную проверку формата сертификатов

Представленные решения помогут вам успешно выполнять HTTPS-запросы с аутентификацией по SSL-сертификатам в Delphi. Всегда проверяйте формат ваших сертификатов и учитывайте особенности работы OpenSSL с различными кодировками файлов.

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

Контекст описывает решение ошибки "No start line" при загрузке SSL-сертификатов в Delphi с компонентами Indy, предлагая методы устранения проблем с форматированием, BOM и путями к файлам.


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

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




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


:: Главная :: Ошибки и Исключения ::


реклама


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

Время компиляции файла: 2024-12-22 20:14:06
2025-08-02 08:42:17/0.0061929225921631/0