1

我正在尝试使用 Botan 库生成分离的签名文件。生成的签名文件未经 OpenSSL 验证(没有其他检查)。提示签名文件的形成可能有什么错误。

几个用于签名的密钥和证书存储在 HSM 中,获取它们并不难。对于我使用 RSA 密钥和 SoftHSM 的测试,稍后将使用另一种密钥格式和物理 HSM。PKCS#11 用于与 HSM 通信。

对于创建 PKCS#7:

static const Botan::BigInt CMSVersion(1ull);

std::vector<uint8_t> createAttributes(std::vector<uint8_t> &digestData)
{
  std::chrono::time_point<std::chrono::system_clock> time = std::chrono::system_clock::now();
  Botan::OID dataOID("1.2.840.113549.1.7.1");
  Botan::Attribute contentType(Botan::OIDS::str2oid("PKCS9.ContentType"),
                               dataOID.BER_encode());
  Botan::X509_Time timeASN1(time);
  std::vector<uint8_t> attributesData;
  Botan::DER_Encoder attrib(attributesData);
  attrib.start_cons(Botan::ASN1_Tag(0),
                    Botan::ASN1_Tag(Botan::ASN1_Tag::CONTEXT_SPECIFIC));
  attrib.encode(contentType)
      .start_cons(Botan::ASN1_Tag::SEQUENCE)
        .encode(Botan::OID("1.2.840.113549.1.9.5"))
        .start_cons(Botan::ASN1_Tag::SET).encode(timeASN1).end_cons()
      .end_cons()
      .start_cons(Botan::ASN1_Tag::SEQUENCE)
        .encode(Botan::OIDS::str2oid("PKCS9.MessageDigest"))
        .start_cons(Botan::ASN1_Tag::SET)
          .encode(digestData, Botan::ASN1_Tag::OCTET_STRING,
                  Botan::ASN1_Tag::OCTET_STRING, Botan::ASN1_Tag::UNIVERSAL)
        .end_cons()
      .end_cons();
  attrib.end_cons();
  return attributesData;
}
std::vector<uint8_t> createCMS(const Botan::AlgorithmIdentifier &digestAlg,
                               Botan::X509_Certificate &cert,
                               const Botan::AlgorithmIdentifier &keyAlg,
                               std::vector<uint8_t> &sigData,
                               std::vector<uint8_t> &signedAttributes)
{
  Botan::secure_vector<uint8_t> msgData;
  Botan::DER_Encoder encoder(msgData);
  encoder.start_cons(Botan::ASN1_Tag::SEQUENCE).encode(CMSVersion)
          .start_cons(Botan::ASN1_Tag::SET).start_cons(Botan::ASN1_Tag::SEQUENCE)
            .encode(digestAlg.get_oid()).end_cons().end_cons();
  Botan::OID dataOID("1.2.840.113549.1.7.1");
      encoder.start_cons(Botan::ASN1_Tag::SEQUENCE).encode(dataOID).end_cons();
  encoder.start_cons(Botan::ASN1_Tag::UNIVERSAL, Botan::ASN1_Tag::PRIVATE)
          .encode(cert).end_cons();
  encoder.start_cons(Botan::ASN1_Tag::SET);
  Botan::secure_vector<uint8_t> signerInfoData;
  Botan::DER_Encoder signerInfo(signerInfoData);
  signerInfo.start_cons(Botan::ASN1_Tag::SEQUENCE);
  signerInfo.encode(CMSVersion);
  signerInfo.start_cons(Botan::ASN1_Tag::SEQUENCE)
         .encode(cert.issuer_dn())
         .encode(Botan::BigInt(cert.serial_number())).end_cons();
  signerInfo.start_cons(Botan::ASN1_Tag::SEQUENCE).encode(digestAlg.get_oid())
          .end_cons();
  signerInfo.raw_bytes(signedAttributes);
  signerInfo.encode(keyAlg)
          .encode(sigData, Botan::ASN1_Tag::OCTET_STRING,
                  Botan::ASN1_Tag::OCTET_STRING, Botan::ASN1_Tag::UNIVERSAL);        
  signerInfo.end_cons();
  encoder.raw_bytes(signerInfoData).end_cons().end_cons();
  std::vector<uint8_t> resulData;
  Botan::DER_Encoder result(resulData);
  result.start_cons(Botan::ASN1_Tag::SEQUENCE)
          .encode(Botan::OID("1.2.840.113549.1.7.2"))
          .start_cons(Botan::ASN1_Tag::UNIVERSAL, Botan::ASN1_Tag::PRIVATE)
          .raw_bytes(msgData).end_cons().end_cons();
  return resulData;
}

使用 PKCS#11 计算哈希和签名,如下所示:

 QFile input(m_content->text()), output(m_sigFile->text());
  if(!input.open(QFile::ReadOnly))
  {
    QMessageBox::critical(this, tr("Error"),
                          tr("Content file '%1' not open.\n"
                             "Error message: %2").arg(m_content->text())
                          .arg(input.errorString()));
    return;
  }
  Botan::PKCS11::PKCS11_X509_Certificate *cert = nullptr;
  Botan::Private_Key *key = nullptr;
  // извлечение ключа и сертификата из токена
  while(!input.atEnd())
    {
      static const qint64 maxLen = 1024;
      QByteArray data = input.read(maxLen);
      (*module)->C_DigestUpdate(session->handle(),
                                reinterpret_cast<uchar*>(data.data()),
                                data.size(), &rv);
      if(rv != Botan::PKCS11::ReturnValue::OK)
      {
        QMessageBox::critical(this, tr("Error"),
                              tr("Digest not run.\nError code: 0x%3")
                              .arg(static_cast<int>(rv), 0, 16));
        delete key;
        delete cert;
        delete session;
        delete slot;
        delete module;
        return;
      }
    }
    digest.resize(102400);
    ulong digestLen;
    (*module)->C_DigestFinal(session->handle(), digest.data(), &digestLen, &rv);
    if(rv != Botan::PKCS11::ReturnValue::OK)
    {
      QMessageBox::critical(this, tr("Error"),
                            tr("Digest not start.\nError code: 0x%3")
                            .arg(static_cast<int>(rv), 0, 16));
      delete key;
      delete cert;
      delete session;
      delete slot;
      delete module;
      return;
    }
    digest.resize(digestLen);
    {
      Botan::PKCS11::PKCS11_RNG rng(*session);
      std::unique_ptr<Botan::PK_Ops::Signature> signer =
          key->create_signature_op(rng,
                                   "EMSA3(SHA-256)",
                                   "");
      signer->update(digest.data(), digest.size());
      std::vector<uint8_t> attr = createAttributes(digest);
      auto signData = signer->sign(rng);
      for(uint8_t i : signData)
        signature.push_back(i);
      Botan::AlgorithmIdentifier digAlg("SHA-256", {});
      auto fileData = createCMS(digAlg, *cert, key->algorithm_identifier(),
                                signature, attr);
      output.write(reinterpret_cast<const char*>(fileData.data()),
                   fileData.size());
      output.close();
    }

检查收到的签名文件时,OpenSSL 说

Verification failure
140365848428992:error:04091068:rsa routines:int_rsa_verify:bad signature:../crypto/rsa/rsa_sign.c:220:
140365848428992:error:2E09A09E:CMS routines:CMS_SignerInfo_verify_content:verification failure:../crypto/cms/cms_sd.c:842:
140365848428992:error:2E09D06D:CMS routines:CMS_verify:content verify error:../crypto/cms/cms_smime.c:393:
4

0 回答 0