如何通过 OpenSSL 编程方式创建自签名证书(即不使用“openssl”CLI命令)?

4
我的程序使用OpenSSL,并需要按需创建自签名证书。运行该程序的系统无法访问“openssl”CLI命令,因此我不能使用它。相反,我需要使用OpenSSL X509 API来实现这一目标。
请注意,我不需要创建证书文件,只需要创建一个证书;OpenSSL称之为“X509”结构。
我找不到任何关于如何实现这一点的文档。
我该怎么做?
谢谢。

如果您获取了openssl源代码并查看req.c文件中的apps目录,您可以看到OpenSSL二进制文件是如何实现的。具体来说,您需要查看-x509和-new标志,这会导致它创建一个新请求并自签名。 - Paul Kehrer
2个回答

7

以下是一段可能有用的示例代码

X509 *certificate = NULL;
EVP_PKEY *pkey = NULL;
int   ASN1_INTEGER *serialNumber = NULL;
int i = 0;
RSA *rsaKeyPair = NULL;
BIGNUM *e = NULL;
X509_NAME *name = NULL;
time_t currentTime;

certificate = X509_new();


rsaKeyPair = RSA_new();
e = BN_new();

BN_set_word(e, 65537);


if (!RSA_generate_key_ex(rsaKeyPair, 1024, e, NULL))
{
  ret = error;
}

/* the big number is no longer used */
BN_free(e);
e = NULL;



 EVP_PKEY_assign_RSA(pkey,rsaKeyPair))


  /* no more use for rsaKeyPair */
  rsaKeyPair = NULL;


  (void)X509_set_version(certificate,2);

  /*Allocate and create serial number*/
  serialNumber = M_ASN1_INTEGER_new();

  /*implement serial number algorithm here*/
  CreateSerialNumber(serialNumber);

  /* set the serial number */
  (void)X509_set_serialNumber(certificate,serialNumber);

  /*Serial number set to certificate, free it now*/
  M_ASN1_INTEGER_free(serialNumber); 
  serialNumber = NULL;

  /* set the validity */
  currentTime = time(0);

  X509_gmtime_adj(X509_get_notBefore(certificate), 0);

  X509_gmtime_adj(X509_get_notAfter(certificate), 1000);

  /* set the public key from the privateKey structure into the certificate structure */
  X509_set_pubkey(certificate,pkey);

  /* get the subject name pointer */
  name = X509_get_subject_name(certificate);}


/* country */
 X509_NAME_add_entry_by_txt(
  name,"C",MBSTRING_ASC, (unsigned char *)creationParams->Country, -1, -1, 0);

 !X509_NAME_add_entry_by_txt(name,"O", MBSTRING_ASC, (unsigned char*) "sample", -1, -1, 0);


X509_NAME_add_entry_by_txt(
  name,"CN",MBSTRING_ASC, (unsigned char*) creationParams->CommonName, -1, -1, 0);

 /* its self signed: set issuer name = subject  */
 X509_set_issuer_name(certificate,name);

 /* sign the certificate using sha-1 */
X509_sign(certificate,pkey,EVP_sha1());

这让我找到了正确的方向。具体而言,我在OpenSSL代码(在demos/selfsign.c中)中找到了类似的代码。我将把你的代码与它结合起来,并发布我认为是最简单的解决方案。谢谢! - Martin Del Vecchio

4

我将@Sreekanth的代码与OpenSSL分发中发现的代码(在demos/selfsign.c中)结合起来。这是我能想到最简单的:

X509 *CreateCertificate (char *Country, char *OrganizationName, char *CommonName, char *DNSName, int Serial, int DaysValid)
   {  X509 *Cert = NULL;
      EVP_PKEY *PrivateKey = NULL;
      X509_NAME *Name = NULL;
      RSA *KeyPair = NULL;
      BIGNUM *BigNumber = NULL;
      int Success = 0;

   // Faux loop...
   do {
      // Create the certificate object
      Cert = X509_new();
      if (!Cert)
         break;

      // Set version 2, and get version 3         
      X509_set_version (Cert, 2);

      // Set the certificate's properties
      ASN1_INTEGER_set (X509_get_serialNumber (Cert), Serial);
      X509_gmtime_adj (X509_get_notBefore (Cert), 0);
      X509_gmtime_adj (X509_get_notAfter (Cert), (long)(60 * 60 * 24 * (DaysValid ? DaysValid : 1)));
      Name = X509_get_subject_name (Cert);
      if (Country && *Country)
         X509_NAME_add_entry_by_txt (Name, "C", MBSTRING_ASC, Country, -1, -1, 0);
      if (CommonName && *CommonName)
         X509_NAME_add_entry_by_txt (Name, "CN", MBSTRING_ASC, CommonName, -1, -1, 0);
      if (OrganizationName && *OrganizationName)
         X509_NAME_add_entry_by_txt (Name, "O", MBSTRING_ASC, OrganizationName, -1, -1, 0);
      X509_set_issuer_name (Cert, Name);

      // Set the DNS name
      if (DNSName && *DNSName)
         {  X509_EXTENSION *Extension;
            char Buffer[512];

         // Format the value
         sprintf (Buffer, "DNS:%s", DNSName);
         Extension = X509V3_EXT_conf_nid (NULL, NULL, NID_subject_alt_name, Buffer);
         if (Extension)
            {
            X509_add_ext (DynamicCert->Certificate, Extension, -1);
            X509_EXTENSION_free (Extension);
            }
         }

      // Create the RSA key pair object
      KeyPair = RSA_new();
      if (!KeyPair)
         break;

      // Create the big number object
      BigNumber = BN_new();
      if (!BigNumber)
         break;

      // Set the word      
      if (!BN_set_word (BigNumber, 65537))
         break;

      // Generate the key pair; lots of computes here         
      if (!RSA_generate_key_ex (KeyPair, 1024, BigNumber, NULL))
         break;

      // Now we need a private key object
      PrivateKey = EVP_PKEY_new();
      if (!PrivateKey)
         break;

      // Assign the key pair to the private key object
      if (!EVP_PKEY_assign_RSA (PrivateKey, KeyPair))
         break;

      // KeyPair now belongs to PrivateKey, so don't clean it up separately
      KeyPair = NULL;

      // Set the certificate's public key from the private key object
      if (!X509_set_pubkey (Cert, PrivateKey))
         break;

      // PrivateKey now belongs to Cert, so don't clean it up separately
      PrivateKey = NULL;

      // Sign it with SHA-1
      if (!X509_sign (Cert, PrivateKey, EVP_sha1()))
         break;

      // Success               
      Success = 1;

      } while (0);         

   // Things we always clean up
   if (BigNumber)
      BN_free (BigNumber);
   if (PrivateKey)
      EVP_PKEY_free (PrivateKey);

   // Things we clean up only on failure
   if (!Success)
      {
      if (Cert)
         X509_free (Cert);
      if (PrivateKey)
         EVP_PKEY_free (PrivateKey);
      if (KeyPair)
         RSA_free (KeyPair);
      Cert = NULL;
      }

   // Return the certificate (or NULL)
   return (Cert);         
   }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接