Что такое код openssl_pkcs7_sign


openssl_pkcs7_sign

openssl_pkcs7_sign — подписывает сообщение S/MIME.

Описание

bool openssl_pkcs7_sign (string infilename, string outfilename, mixed signcert, mixed privkey, array headers [, long flags [, string extracertsfilename]])

Эта функция — ЭКСПЕРИМЕНТАЛЬНАЯ. Поведение, имя и всё остальное, что задокументировано для данной функции может быть изменено в будущих релизах РНР без предупреждения. Вы можете использовать эту функцию только на свой страх и риск.

openssl_pkcs7_sign() принимает содержимое файла infilename и подписывает его с использованием сертификата и совпадающего private-ключа, специфицированных параметрами signcert и privkey .

headers это массив шапок/headers, которые будут присоединяться впереди данных после их подписывания (см. в openssl_pkcs7_encrypt() о формате этого параметра).

openssl_pkcs7_sign

openssl_pkcs7_sign — подписывает сообщение S/MIME.

Описание

bool openssl_pkcs7_sign (string infilename, string outfilename, mixed signcert, mixed privkey, array headers [, long flags [, string extracertsfilename]])

Предупреждение!

Эта функция — ЭКСПЕРИМЕНТАЛЬНАЯ. Поведение, имя и всё остальное, что задокументировано для данной функции может быть изменено в будущих релизах РНР без предупреждения. Вы можете использовать эту функцию только на свой страх и риск.

openssl_pkcs7_sign() принимает содержимое файла infilename и подписывает его с использованием сертификата и совпадающего private-ключа, специфицированных параметрами signcert и privkey.

headers это массив шапок/headers, которые будут присоединяться впереди данных после их подписывания (см. в openssl_pkcs7_encrypt() о формате этого параметра).

flags можно использовать для изменения вывода — см. PKCS7-константы; если не специфицирован, по умолчанию будет PKCS7_DETACHED.

extracerts специфицирует имя файла, содержащего узел дополнительных сертификатов для включения в подпись, что может использоваться, например, для того, чтобы принимающий мог проверить сертификат, используемый вами.

Пример 1. openssl_pkcs7_sign()

Примечание: эта функция была добавлена в 4.0.6.

Что такое код openssl_pkcs7_sign

652 просмотра

1 ответ

6084 Репутация автора

Я использую TCPDF для создания PDF-документа и подписать его. Сам TCPDF просто вызывает openssl_pkcs7_sign функцию PHP , которая, как мне кажется, вызывает PKCS7_sign функцию Си на основе исходного кода .

До недавнего времени все работало нормально. Затем я сменил поставщика сертификатов. Я только что обновил закрытый ключ, сертификат и цепочку сертификатов:

Я скопировал новый корневой сертификат и промежуточный сертификат в формате PEM внутри extra_certificates_path файла. Я проверил этот файл, используя, openssl и, кажется, хорошо.

Теперь, когда я открываю подписанный PDF в Adobe Reader, он показывает эти ошибки:

    Открывая файл, он говорит

Этот файл поврежден, но восстанавливается

Есть ошибки в форматировании или информации, содержащейся в этой подписи (информация о поддержке: SigDict / Contents недопустимые данные)

Смотрите скриншот ниже.

Есть идеи, что может быть не так?

Ответы (1)

3 плюса

60274 Репутация автора

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

Таким образом, решение состоит в том, чтобы зарезервировать больше места для контейнера подписи.

И действительно, ОП подтвердил:

Действительно, было место, которое указывало максимальную длину подписи. Я изменил это, и это работает.

Кроме того, ФП выразил свою заинтересованность в том, как определить проблему для начала.

Для решения многих проблем с PDF вы начинаете с проверки PDF с помощью внутреннего PDF-браузера, такого как iText RUPS или PDFBox PDFDebugger. В этом случае, однако, достаточно просмотра текста и просмотра в шестнадцатеричном формате.

Использование просмотра текста можно найти в словаре значение подписи (довольно отпечатанных здесь, то Contents запись укорачивается):

Запись ByteRange указывает, что значение Contents (контейнер с шестнадцатеричной кодировкой подписи) должно достигать от смещения файла 78679 до 90423-1. Используя шестнадцатеричный просмотрщик, вы быстро проверяете, совпадает ли начальный индекс значения Contents ( ), но конечный индекс имеет более поздний индекс, чем ожидалось.

Вот вам, слишком большой контейнер для подписи. ;)

Open SSL

Cryptography and SSL/TLS Toolkit

PKCS7_sign

PKCS7_sign — create a PKCS#7 signedData structure

SYNOPSIS

DESCRIPTION

PKCS7_sign() creates and returns a PKCS#7 signedData structure. signcert is the certificate to sign with, pkey is the corresponding private key. certs is an optional additional set of certificates to include in the PKCS#7 structure (for example any intermediate CAs in the chain).

The data to be signed is read from BIO data.

flags is an optional set of flags.

Any of the following flags (ored together) can be passed in the flags parameter.

Many S/MIME clients expect the signed content to include valid MIME headers. If the PKCS7_TEXT flag is set MIME headers for type text/plain are prepended to the data.

If PKCS7_NOCERTS is set the signer’s certificate will not be included in the PKCS7 structure, the signer’s certificate must still be supplied in the signcert parameter though. This can reduce the size of the signature if the signers certificate can be obtained by other means: for example a previously signed message.

The data being signed is included in the PKCS7 structure, unless PKCS7_DETACHED is set in which case it is omitted. This is used for PKCS7 detached signatures which are used in S/MIME plaintext signed messages for example.

Normally the supplied content is translated into MIME canonical format (as required by the S/MIME specifications) if PKCS7_BINARY is set no translation occurs. This option should be used if the supplied data is in binary format otherwise the translation will corrupt it.

The signedData structure includes several PKCS#7 authenticatedAttributes including the signing time, the PKCS#7 content type and the supported list of ciphers in an SMIMECapabilities attribute. If PKCS7_NOATTR is set then no authenticatedAttributes will be used. If PKCS7_NOSMIMECAP is set then just the SMIMECapabilities are omitted.

If present the SMIMECapabilities attribute indicates support for the following algorithms: triple DES, 128 bit RC2, 64 bit RC2, DES and 40 bit RC2. If any of these algorithms is disabled then it will not be included.

If the flags PKCS7_STREAM is set then the returned PKCS7 structure is just initialized ready to perform the signing operation. The signing is however not performed and the data to be signed is not read from the data parameter. Signing is deferred until after the data has been written. In this way data can be signed in a single pass.

If the PKCS7_PARTIAL flag is set a partial PKCS7 structure is output to which additional signers and capabilities can be added before finalization.

If the flag PKCS7_STREAM is set the returned PKCS7 structure is not complete and outputting its contents via a function that does not properly finalize the PKCS7 structure will give unpredictable results.

Several functions including SMIME_write_PKCS7(), i2d_PKCS7_bio_stream(), PEM_write_bio_PKCS7_stream() finalize the structure. Alternatively finalization can be performed by obtaining the streaming ASN1 BIO directly using BIO_new_PKCS7().

If a signer is specified it will use the default digest for the signing algorithm. This is SHA1 for both RSA and DSA keys.

The certs, signcert and pkey parameters can all be NULL if the PKCS7_PARTIAL flag is set. One or more signers can be added using the function PKCS7_sign_add_signer(). PKCS7_final() must also be called to finalize the structure if streaming is not enabled. Alternative signing digests can also be specified using this method.

If signcert and pkey are NULL then a certificates only PKCS#7 structure is output.

In versions of OpenSSL before 1.0.0 the signcert and pkey parameters must NOT be NULL.

Some advanced attributes such as counter signatures are not supported.

RETURN VALUES

PKCS7_sign() returns either a valid PKCS7 structure or NULL if an error occurred. The error can be obtained from ERR_get_error(3).

SEE ALSO

HISTORY

The PKCS7_PARTIAL flag, and the ability for certs, signcert, and pkey parameters to be NULL were added in OpenSSL 1.0.0.

The PKCS7_STREAM flag was added in OpenSSL 1.0.0.

Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved.

Licensed under the Apache License 2.0 (the «License»). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at https://www.openssl.org/source/license.html.

master manpages

This manpage

Please report problems with this website to webmaster at openssl.org.

Copyright © 1999-2020, OpenSSL Software Foundation.

Почему для OpenSSL PKCS7_verify () требуется сертификат «smimesign»?

Страница PKCS7_verify() для PKCS7_verify() гласит, что

. Each signer’s certificate is chain verified using the smimesign purpose.

Почему именно эта цель всегда требуется? Я понимаю, что подписанная структура PKCS7 может использоваться для многих целей, и S / MIME является лишь одним из них.

Если мой сертификат подписи не имеет smimeSign среди своих extendedKeyUsage , PKCS7_verify() завершается ошибкой. Мне нужно вручную настроить purpose , чтобы сделать проверку. Я что-то здесь упускаю?

1 ответ

Недостаточно просто проверить подпись, проверить подлинность сертификата подписавшего и цепочку, ведущую к доверенному корню. Любой проверочный код также должен гарантировать, что владелец сертификата имеет право выполнить подпись для конкретной цели. Проверка получения сертификата, имеющего привилегию smimeSign , намного менее строгая, чем проверка, скажем, сертификата подписи кода.

Представьте себе компанию по разработке программного обеспечения, где каждому сотруднику был выдан сертификат для подписи и шифрования электронной почты. Эта компания также выпускает программный продукт и предоставляет подписанный дистрибутив PKCS # 7 своего продукта. Если функции проверки PKCS # 7 не проверяли цель подписывающего сертификата (в этом случае мы хотели бы иметь codesign обозначение), плохой актер в компании может создать скомпрометированную версию программного продукта и подписать ее своим E-Mail сертификат (который имеет только цель smimesign .)

В случае pkcs7_verify() OpenSSL, API был разработан, чтобы подразумевать цель вместо того, чтобы явно требовать ее передачи, и smimeSign был выбран по умолчанию. Я предполагаю, что, поскольку S / MIME является наиболее распространенным использованием PKCS # 7, это имело смысл, и это позволяет кому-то проверять PKCS # 7 в большинстве случаев использования без необходимости изучать extendedKeyUsage .

[Ниже моего первоначального ответа на ваш вопрос перед редактированием « Могу ли я указать, что я хочу проверить подпись в PKCS7 для какой-либо другой цели» :]

Сертификат может содержать (необязательный) атрибут, который называется «Расширенное использование ключа». Этот атрибут используется для указания того, для чего разрешено использовать сертификат. Некоторые возможные варианты использования X509.v3:

  • serverAuthentication
  • clientAuthentication
  • CodeSigning
  • emailProtection
  • ipSecEndSystem
  • ipSecTunnel
  • проставление даты
  • ocspSigning
  • smartCardLogin
  • pkiPeerAuth

Вы можете проверить страницу руководства x509v3_config на наличие флагов использования ключей, о которых знает openssl.

PKCS # 7 — это общий формат контейнера, который позволяет как подписывать, так и шифровать содержимое контейнера. S / MIME использует PKCS # 7 для подписи и / или шифрования сообщений электронной почты, и в этом случае используемый сертификат должен иметь использование emailProtection.

Если вы хотите распространить некоторый код и хотите, чтобы получатель мог убедиться, что рассылка от вас и не изменена, вы можете использовать PKCS # 7 для распространения, и в этом случае ваш сертификат должен иметь расширенный ключ codeSigning. атрибут использования. Сертификат может иметь несколько вариантов использования ключа, но в целом рекомендуется иметь отдельный ключ (и, следовательно, сертификат) для разных типов использования.

Openssl в командной строке поддерживает указание желаемого назначения сертификата при использовании команды «openssl smime». Например,

проверит подпись в файле «my file.p7p», запишет содержимое контейнера PKCS # 7 в файл «my-p7-content» и примет любой действительный сертификат, независимо от того, для чего он предназначен. (-целевой любой). Обратите внимание, что на man-странице openssl для smime параметр -purpose не указан в качестве опции, но он действительно поддерживается.

Поскольку вы цитируете документацию по API PKCS7_verify программно, вы можете указать цель с помощью метода X509_VERIFY_PARAM_set_purpose при настройке объекта X509_STORE. Следующий фрагмент должен дать вам представление о процессе:

Это установит цель для SSL-клиента при проверке.

Ошибка подписания PDF с openssl_pkcs7_sign РНР

Я использую TCPDF для создания PDF — документа и подписать его. Сам TCPDF просто вызывает РНР openssl_pkcs7_sign функцию, которая кажется мне позвонит Кассиопеяну PKCS7_sign функции на основе исходного кода .

До недавнего времени все не работали нормально. Затем я изменил поставщика сертификата. Я только что обновил закрытый ключ, сертификат и цепочку сертификатов:

Я скопировал новый корневой сертификат и промежуточный сертификат в формате PEM внутри extra_certificates_path файла. Я проверил этот файл , используя openssl и, кажется , хорошо.

Теперь, когда я открываю подписанный PDF в Adobe Reader, он показывает эти ошибки:

    При открытии файла, он говорит

Этот файл поврежден, но ремонтируется

Сертификация является недействительной

Есть ошибки в форматировании или информации, содержащейся в этой подписи (вспомогательная информация: SigDict / Contents нелегальных данных)

Смотрите скриншот ниже.

Любая идея, что может быть не так?

Анализируя пример файл разделявшегося OP можно понять проблему: Сигнатура контейнер встроенный в документ превышает размер первоначально зарезервирован для него.

Таким образом, решение резервировать больше места для контейнера подписи.

И действительно, ОП подтвердил:

Действительно было место, которое указано на максимальную длину подписи. Я изменил его, и он работает.

Кроме того, О.П. указал свой интерес, как определить проблему, чтобы начать с.

Для многих задач PDF один начинается путем проверки PDF с помощью браузера PDF Internals как IText RUPS или PDFBox PDFDebugger. В этом случае, хотя, для просмотра текста и шестнадцатеричной зритель достаточно.

Использование просмотра текста можно найти в словаре значение подписи (довольно отпечатанных здесь, то Contents запись укорачивается):

ByteRange запись означает , что содержание значение (шестнадцатеричный кодируются контейнер подписи) должны достигнуть из файла смещение 78679 до 90423-1. Используя шестигранный зрителя один быстро проверяет , что исходный индекс Содержание значения ( ) соответствует , но конечный индекс находится на более позднем индексе , чем ожидалось.

Там вы, слишком большой контейнер подписи заливали. ;)

Подключаем Рутокен ЭЦП к OpenSSL

UPDATE. Готовое решение для электронной подписи в браузере — Рутокен Плагин


Как известно, OpenSSL версии 1.0.0 и старше поддерживает российские криптоалгоритмы ГОСТ, причем поддержка этих алгоритмов полнофункциональна: реализованы подпись и шифрование в форматах PKCS#7, CMS, S/MIME в соответствии с российскими стандартами и RFC; протокол TLS с поддержкой российских шифрсьютов и т.п.

Таким образом, OpenSSL полностью совместим с проприетарными средствами криптозащиты российских производителей.

Для поддержки ГОСТов в него добавлен специальный «плагин» — engine gost. Вместе с тем существуют криптографические USB-токены с аппартной реализацией российских криптоалгоритмов на «борту». Примером такого токена является Рутокен ЭЦП, который, кстати сказать, сертифицирован как СКЗИ по классу КС2. Рутокен ЭЦП можно подключить к OpenSSL таким образом, что криптографические операции будут делаться на «борту» токена.

Для Рутокен ЭЦП имеется специальный кроссплатформенный плагин к OpenSSL — engine pkcs11_gost, который позволяет использовать аппаратную релизацию ГОСТов через стандартный интерфейс OpenSSL.

Здесь опишу, как это делается на win32.

1. OpenSSL можно взять отсюда www.slproweb.com/products/Win32OpenSSL.html. При установке в диалоге “Select Additional Tasks” следует выбрать “The OpenSSL” binaries (/bin) directory”.

3. Содержимое архива следует скопировать в папку установки OpenSSL/bin. При этом конфиг openssl. cfg надо заменить, так как в архиве содержится конфиг заточенный на использование engine pkcs11_gost.

4. Затем запускаем cmd.exe (ну или кому что нравится) и указываем в переменных окружения наш конфиг SET OPENSSL_CONF=полный путь к файлу конфигурации openssl.cfg.

5. Теперь нужно установить драйвера Рутокен, подключить к компьютеру Рутокен ЭЦП и отформатировать его через Панель управления->Панель управления Рутокен.

Используя утилиту openssl.exe пройдем путь, который позволит нам подписать файл. При этом криптографические операции (а здесь используются генерация ключа и электронная подпись) будут производиться «на борту» Рутокен ЭЦП.

1. Сгенерим ключ подписи ГОСТ Р 34.10-2001:

openssl genpkey -engine pkcs11_gost -algorithm GOST2001 -pkeyopt slot_key_id:50 -pkeyopt paramset:A -pkeyopt pin:12345678

2. Cоздадим заявку на сертификат в формате PKCS#10 для созданного ключа:

openssl req -engine pkcs11_gost -new -key 50 -keyform engine -out req.csr

3. Создадим самоподписанный корневой сертификат, для того чтобы выдать пользовательский сертификат на заявку. Для начала сгенерируем внутри токена ключ УЦ:

openssl genpkey -engine pkcs11_gost -algorithm GOST2001 -pkeyopt slot_key_id:100 -pkeyopt paramset:A -pkeyopt pin:12345678

Затем сами себе выдадим корневой сертификат для этого ключа:

openssl req -engine pkcs11_gost -x509 -new -key 100 -keyform engine -out ca.crt

4. Выпустим сертификат по заявке, полученной на шаге 2. Для этого в папке установки OpenSSL/bin создадим папку demoCA, в которой создадим папку newcerts. В папке demoCA создадим пустой файл index.txt и файл serial, в котором напишем 01. Это позволит нам вести учет выданных сертификатов. Команда выдачи сертификата:

openssl ca -engine pkcs11_gost -keyfile 100 -keyform engine -cert ca.crt -in req.csr -out tester.crt

5. Подпишем произвольный файл “присоединенной” подписью в формате S/MIME:

Sign PKCS#7 and verify PKCS#7 signature with OpenSSL

If someone have to transfer X.509 certificates in a single bundle, usually, it is recommended to pack them into PKCS#7. And content of PKCS#7 can be signed.

OpenSSL allows to pack certificates into PKCS#7 in the following way:

openssl crl2pkcs7 -nocrl -certfile domain.crt -certfile ca-chain.crt -out domain.p7b

As I understand from the man page of ‘openssl crl2pkcs7’, this PKCS#7 is signed:

The output file is a PKCS#7 signed data structure containing no signers and just certificates and an optional CRL.

A few questions here:

  1. What does ‘containing no signers’ mean?
  2. If the content (certificates) of PKCS#7 is not really signed, how can it be done using OpenSSL?
  3. How signature of PKCS#7 can be verified using OpenSSL considering that it was signed?

If I understand overall concept wrongly, please, clarify that.

1 Answer 1

TLDR: It’s not actually signed. You do understand wrongly. To explain I’ll start from the beginning.

PKCS#7, and its slightly modified and enhanced IETFized[1] form CMS Cryptographic Message Syntax http://tools.ietf.org/html/rfc3852 et pred et amici, is a standard that defines a whole series of different but similar messages for various cryptographic functions. One type of PKCS#7/CMS message is called SignedData and its original purpose, as you might reasonably guess, is to convey data with a digital signature, or for generality one or more signatures, for example a contract signed by both parties. PKCS#7 (mostly) uses public-key cryptography and needs/expects a way to properly match public-key values to entities like people and organizations and systems, called a PKI Public Key Intrastructure; in practice the PKI we use is X.509 Certificates issued by CAs Certificate Authorities which can revoke bad certificates using CRLs Certificate Revocation Lists (and nowadays also using OCSP, but that came after PKCS#7).

A SignedData actually consists of three main parts: the actual data in a structure named ContentInfo; a variable number of SignerInfo structures each containing one signature and some metadata including an identification of the certificate containing the public-key needed to verify the signature; and a variable number (maybe none) of certificates and/or CRLs that the recipient may need to determine and verify the (signing) public-keys or for any purpose. For generality the number of SignerInfo’s, and thus signatures, may be zero, in which case the data is useless and is omitted.

Thus a SignedData with no data and no «signers» (zero SignerInfo structures), only certificates and/or CRLs, provided a standardized format to contain several related certificates and/or CRLs, at an early date when there was no other good standardized method for this. As a result it was widely adopted and became ubiquitous. This format is commonly identified by the extensions «p7b» and «p7c». See What’s the difference between X.509 and PKCS#7 Certificate? .

So as to your questions: this format is a PKCS#7 or CMS structure of the type named SignedData, but it does not actually contain data or signature(s) on that data, it contains only certificates and/or CRLs. Because it isn’t signed, it can’t itself be verified.

Each certificate or CRL in itself is signed, using a signature specific to the cert/CRL format not a general data signature. This is independent of whether it is in a p7b or separate. Each (nonroot) cert or CRL after you extract it can be verified, if you have a valid chain of certs «above» it, and should be if you use it for anything. However all PKI signatures only propagate trust from a (usually small) set of trusted «roots» or «anchors» (such as Verisign, GoDaddy, etc but hopefully not DigiNotar) to an unboundedly large set of other entities (HTTPS or other SSL/TLS servers on the net, email senders in the world, program developers in the world, etc). Ultimately you decide what anchors to trust, or delegate that decision to someone (like Microsoft for Windows, Oracle for Java, Mozilla for Firefox, etc).

In OpenSSL all (AFAICS) operations that use certificates, and (optionally) CRLs, verify them, against a truststore of CA (root) certs that you can choose or default. You can also manually (re)verify a cert with the commandline verify utility; see https://www.openssl.org/docs/apps/verify.html . Other tools and programs will do something equivalent, but details vary some.

[1] for comparison, the Netscape protocol SSL Secure Sockets Layer was turned over to IETF where it was slightly modified and enhanced and renamed TLS Transport Layer Security. Although there are technical differences that do matter sometimes (like the recent POODLE vulnerability that affects SSL but is fixed in TLS, at least in correct implementations), for the most part SSL and TLS are functionally the same and people often just say SSL to mean both. Similarly PKCS#7 and CMS are so similar many people use either name for both.

Update 2/06 per comment: If you send a valid chain to a recipient who correctly validates the lowest (leaf) cert using that chain, that will prove whether the chain is valid as received.

  • If an attacker or fault modifies or deletes any (needed) cert or replaces one with an invalid or wrong cert, the received chain won’t validate.
  • If an uneeded cert (either valid or not) is added it won’t be detected, but won’t harm security at the recipient either.
  • If you sent an unneeded cert (or several) and that uneeded cert(s) is modified, deleted or replaced it won’t be detected, and won’t harm.
  • If you omitted a needed cert and it is added (particularly an intermediate CA cert is likely to be widely known and available), the recipient won’t detect the change, but security will be helped.
  • If there are multiple valid chains — as is often the case with public CAs, especially now when many have recently upgraded to one or more of RSA-2k ECC SHA2 — if you send one chain and it is modified to another chain that is also valid, the recipient won’t detect the change. This is the only case I can see where the recipient can be harmed: if there are multiple valid chains but not equally «good» on some metric, like long-term sustainability, the recipient can be tricked into using a worse one.

PKCS#7/CMS can be nested. This is commonly used to both sign and encrypt (aka envelope) but other combinations are possible. If you really care the recipient get the exact chain (or other set) you send, not just a valid chain, you can put the p7b as the content of a second, outer SignedData message. In this case you have another choice: mostly for historical reasons PKCS#7/CMS can generate a «detached» signature, where the SignedData object does not actually contain the data, only the SignerInfo(s) and some metadata like the hash algorithm(s); in this case you must send both chunks of data in a way that the recipient can reliably connect them, e.g. Message12345.dat and Message12345.sig . Alternatively it can «embed» the data in the content slot of the SignedData message; this is probably simpler for your case. OpenSSL commandline can do this just by doing two steps, and much email software can handle the SignedData part or at least its S/MIME variants (which OpenSSL can also do), and the remaining p7b part can be handled by most if not all cert/security software.

RFC 4510 (and 2510) has lots of capabilities and options that I haven’t dug through, and I’ll readily believe there’s something in there that does what you want, but I’ve never seen any implementation of it. You may well have to write — and support — the software at both (or all?) ends yourself.

Как подписать и расшифровать Сообщ с openssl_pkcs7_sign

Я написание WordPress Оплата плагин, в некоторых из кода , который я должен использовать openssl_pkcs7_sign для знака сообщения и отправить на банковский шлюз и получить маркер. для этого

первый сохранить сообщение в msg.txt сообщении , как это:

и файл cert.pem содержат

Теперь мой вопрос

  1. зачем использовать файл? Я хочу использовать массив вместо файла.
  2. как можно обеспечить мой знак сообщение верно?
  3. почему подписать и не расшифровывать?
  4. как беззнаковое сообщение снова
  5. с помощью команды OpenSSL в терминале, как тест проверить знак сообщение и знак?

openssl_pkcs7_sign

(PHP 4 >= 4.0.6, PHP 5, PHP 7)

openssl_pkcs7_sign — Sign an S/MIME message

Description

openssl_pkcs7_sign() takes the contents of the file named infilename and signs them using the certificate and its matching private key specified by signcert and privkey parameters.

Parameters

headers is an array of headers that will be prepended to the data after it has been signed (see openssl_pkcs7_encrypt() for more information about the format of this parameter).

flags can be used to alter the output — see PKCS7 constants.

extracerts specifies the name of a file containing a bunch of extra certificates to include in the signature which can for example be used to help the recipient to verify the certificate that you used.

Return Values

Returns TRUE on success or FALSE on failure.

Examples

Example #1 openssl_pkcs7_sign() example

// the message you want to sign so that recipient can be sure it was you that
// sent it
$data =
You have my authorization to spend $10,000 on dinner expenses.

The CEO
EOD;
// save message to file
$fp = fopen ( «msg.txt» , «w» );
fwrite ( $fp , $data );
fclose ( $fp );
// encrypt it
if ( openssl_pkcs7_sign ( «msg.txt» , «signed.txt» , «mycert.pem» ,
array( «file://mycert.pem» , «mypassphrase» ),
array( «To» => «joes@example.com» , // keyed syntax
«From: HQ » , // indexed syntax
«Subject» => «Eyes only» )
)) <
// message signed — send it!
exec ( ini_get ( «sendmail_path» ) . » );
>
?>

User Contributed Notes

Amongst the many discussions about signing or encrypting email by itself, none really discuss the pain of having an email BOTH signed AND encrypted.

According to RFC 2311, you can encrypt then sign or sign then encrypt. However, it depends on the client in which you are programming for. In my experience, in Outlook 2000, it prefers it Encrypt then Sign. While in Outlook 2003, it is Sign then Encrypt. Generally, you want Sign then Encrypt, as it seems most logical from a snail-mail piece point of view. You first sign a letter than put it in an envelope. Certain clients complain if you do it in an order it does not like, so you may want to experiement with it.

When you perform the first function, do NOT put in any headers in the headers array parameters, you want to put it in the SECOND function you want to perform. If you put the headers in the first function, the second function will hide it from the mail servers. You do not want that. Here I will sign then encrypt.

// Setup mail headers.
$headers = array( «To» => «someone@nowhere.net» ,
«From» => «noone@somewhere.net» ,
«Subject» => «A signed and encrypted message.» );

// Sign the message first
openssl_pkcs7_sign ( «msg.txt» , «signed.txt» ,
«signing_cert.pem» ,array( «private_key.pem» ,
«password» ),array());

// Get the public key certificate.
$pubkey = file_get_contents ( «cert.pem» );

//encrypt the message, now put in the headers.
openssl_pkcs7_encrypt ( «signed.txt» , «enc.txt» ,
$pubkey , $headers , 0 , 1 );

$data = file_get_contents ( «enc.txt» );

// separate header and body, to use with mail function
// unfortunate but required, else we have two sets of headers
// and the email client doesn’t decode the attachment
$parts = explode ( «\n\n» , $data , 2 );

// send mail (headers in the Headers parameter will override those
// generated for the To & Subject parameters)
mail ( $mail , $subject , $parts [ 1 ], $parts [ 0 ]);
?>

Note that if you use a function that picks up the data from the disk to be used in another function in your program, remember that you may have used the explode(«\n\n»,$data,2) function which may have removed the spacing between the header and the message content.

When you take the signed message and feed it in to the encryption part, you have to remember that the line spacing must also be fed AS PART OF THE MESSAGE BODY! If you plan to sign then encrypt, do not feed the header output from the signing into the encrypting as part of the headers array parameter! The output of the signing should stay as part of the message body being encrypted. (And the same is true if you are doing the reverse of encrypting then signing.) An example of both the signing and encryption function made in to a routine for reusability, and then called to sign and encrypt a message.

THIS IS WRONG!:
// [0] of Array contains headers of message. [1] of Array contains signed body of message.
$signedOutputArray = signMessage ( $inputMessage , $headers );

// [0] of Array contains headers of message and the signing.
// [1] of Array contains encrypted body of message without the signing header.
$signedAndEncryptedArray = encryptMessage ( $signedOutputArray [ 1 ],
$signedOutputArray [ 0 ]);

mail ( $emailAddr , $subject , $signedAndEncryptedArray [ 1 ],
$signedAndEncryptedArray [ 0 ]);
?>

THIS IS CORRECT!
// [0] of Array contains headers of signing.
// [1] of Array contains signed body of message.
$signedOutputArray = signMessage ( $inputMessage ,array());

// [0] of Array contains headers of message.
// [1] of Array contains encrypted contents of both the signed message and its headers of the signing.
$signedAndEncryptedArray =
encryptMessage ( $signedOutputArray [ 0 ] . «\n\n» . $signedOutputArray [ 1 ], $headers );

mail ( $emailAddr , $subject , $signedAndEncryptedArray [ 1 ],
$signedAndEncryptedArray [ 0 ]);
?>

I also spent hours when trying to find the reason of error:
«error getting private key».

Sometimes this error appeared, sometimes not.

My solution is using the realpath() for every parameter of openssl_pkcs7_sign. In my case the code looks like:

$clearfile = «certificate/random_name» ;
$encfile = $clearfile . «.enc» ;
$clearfile = $clearfile . «.txt» ;

// —-
// — fill $clearfile with the mail to be signed .
// —-

openssl_pkcs7_sign ( realpath ( $clearfile ),
realpath ( ‘.’ ). ‘/’ . $encfile , // because $encfile does not exist yet we cannot use realpath($encfile);
‘file://’ . realpath ( $Certif_path ),

array( ‘file://’ . realpath ( $Certif_path ), PUBLIC_KEY ),

array( «To» => TO_EMAIL ,
«From» => FROM_EMAIL ,
«Subject» => «» ),

This command doesn’t work correctly on WIN32 with IIS. Mails aren�t interpreted correctly by IIS SMTP Server (and by Outlook too). The reason is that UNIX and WINDOWS interpret the �enter to the next line� ascii code in a different way.

Below I present an improved code:

//save the message to a file
$fp = fopen ( «msg.txt» , «w» );
fwrite ( $fp , $data );
fclose ( $fp );

//sign the message using the sender’s keys
openssl_pkcs7_sign ( «msg.txt» , «signed.eml» , «file://c:/max/cert.pem» ,
array( «file://c:/max/priv.pem» , «your_password» ),
array( «To» => «recipient » ,
«From» => «sender » ,
«Subject» => «Order Notification — Test» ), PKCS7_DETACHED , «c:\max\extra_cert.pem» );

$file_arry = file ( «signed.eml» );
$file = join ( «» , $file_arry );
$message = preg_replace ( «/\r\n|\r|\n/» , «\r\n» , $file );

$fp = fopen ( «c:\Inetpub\mailroot\Pickup\signed.eml» , «wb» );
flock ( $fp , 2 );
fputs ( $fp , $message );
flock ( $fp , 3 );
fclose ( $fp );

?>

Besides, if you want to use the keys created with Windows, you should export them (from IE) to the form of PKCS#12 file (*.pfx).

enter the commands:

-nocerts -nodes -out

Next export from IE Root CA certificate as Base-64 *.cer and rename the file to *.pem

A note about the $flags parameter: PKCS7_BINARY has 2 effects:
* converts LF to CR+LF, as described in http://www.php.net/manual/en/openssl.pkcs7.flags.php
* it creates an opaque pkcs7 signature (p7m)

If you want to prevent the LF->CR+LF conversion *and* still have a detached signature (p7s), use PKCS7_BINARY | PKCS7_DETACHED (both flags are set).

If the signed message is already MIME multi-part, using both flags as described above seems to be the right solution to assemble the message properly. Without any flags, apparently only some of the LF characters are converted. In a specific scenario (the local MTA is Postfix and then the message goes through sendmail on another machine), the MIME boundaries get scrambled in sendmail. However, this doesn’t seem to happen if the local MTA is sendmail.

I would like to make a modification from my previous note. Some clients prefer a certain order in which messages should be signed and encrypted (if both is desired). Newer email clients, such as Thunderbird and Outlook 2003 will accept the most secure method of «sign -> encrypt -> sign again».

The first signing authenticates the message saying that you did indeed write it. Then the email is encrypted so that only the recipient can open and read it. Then the second signing ensure confidentiality by identifying that the person encrypting is the one whom encrypted it, a message intended for the decrypting person. This is the most secure method. This ensures: Non-Repudiation of message (first sign), Confidentiality (encrypt), and Context Integrity [you were intended to be addressed] (second sign).

If you only sign then encrypt, there is no way you can guarantee that (aside from the contents of the letter, headers are placed in plain text outside the message) that the message was intended for you by the original sender. For example:

Bob signs a love letter and encrypts it to Amy saying only «I love you. — Bob». Amy decrypts it, sees the message (and plays a joke) and forwards the message to John using John’s public key, re-encrypting, but not tampering with the message contents keeping the signature valid. This allows Amy to make it look like Bob sent John a love letter and that Bob loves John, as you cannot verify whom sent it during encryption. That is not what you want!

This is also analogous to someone taking a government document, put it in an envelope themselves and write the government address in the return address and send it to you. You know the letter is written by the government, but you don’t know for sure whether the government sent it to you directly or was opened and relayed.

While encrypting then signing has a problem, this is affectively signing on the envelope of a snail mail piece. I know you sent it, but is the message really from you? Or are you forwarding it?

Sign — Encrypt — Sign Again method will make the first sign show that you know the writer of the message is the person, encrypt it to keep others from reading it, sign again to indicate the message was not relayed and that the sender intended to sent the mail to address you.

Just make sure the headers of the mail is applied in the last step and not the second or third step.

For more information about the security and integrity risks of this situation, please read this web page: http://world.std.com/

= Content-Type: text/plain;
charset=»us-ascii»
Content-Transfer-Encoding: 7bit

You have my authorization to spend 10,000 on dinner expenses.
The CEO
EOF;

$fp = fopen ( «msg.txt» , «w» );
fwrite ( $fp , $data );
fclose ( $fp );

$headers = array( «From» => «me@email.com» );

openssl_pkcs7_sign ( «msg.txt» , «signed.txt» , «file://email.pem» , array( «file://email.pem» , «123456» ), $headers );

$data = file_get_contents ( «signed.txt» );

$parts = explode ( «\n\n» , $data , 2 );

mail ( «you@email.com» , «Signed message.» , $parts [ 1 ], $parts [ 0 ]);

echo «Email sent» ;

It is also possible to sign message including attachments. An easy way to do this:

= md5 ( uniqid ( time ()));
$boddy = «MIME-Version: 1.0\n» ;
$boddy .= «Content-Type: multipart/mixed; boundary=\»» . $boundary . «\»\n» ;
$boddy .= «Content-Transfer-Encoding: quoted-printable\n\n» ;
$boddy .= «This is a multi-part message in MIME format.\n\n» ;
$boddy .= «— $boundary \n» ;
$boddy .= «Content-Type: text/plain; charset=\»iso-8859-1\»\n» ;
$boddy .= «Content-Transfer-Encoding: quoted-printable\n\n» ;
$boddy .= $EmailText . «\n\n» ;
// Add the attachment to the message
do <
$boddy .= «— $boundary \n» ;
$boddy .= «Content-Type: application/pdf; name=\»FileName\»\n» ;
$boddy .= «Content-Transfer-Encoding: base64\n» ;
$boddy .= «Content-Disposition: attachment;\n\n» ;
$boddy .= chunk_split ( base64_encode ( $file )) . «\n\n» ;
> while ( < files left to be attached >);
$boddy .= «— $boundary —\n» ;

Илон Маск рекомендует:  Что такое код ncurses_nonl
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL
Предупреждение!