【问题标题】:C++ macOS - Programmatically retrieve code sign certificate informationC++ macOS - 以编程方式检索代码签名证书信息
【发布时间】:2018-04-08 07:42:12
【问题描述】:

在 Windows 上,可以使用 CryptQueryObject 获取 .exe/.dll 代码签名证书。

是否有任何 c++(或 Objective-c)替代方法来检索已用于对 .app 进行代码签名的证书的 主题名称序列号在 macOS 上?

我使用 xcode 对我的 .app 进行代码签名没有问题,当我在终端中时,我能够看到我的代码已使用正确的证书进行签名。


编辑:

我们的想法是得到类似这个命令行的东西,但是在 C++ 中。

codesign -v --extract-certificates MyApp.app/ 
| openssl x509 -inform DER -in codesign0 -text 
| grep "Serial" -A 1

【问题讨论】:

  • 当然,您总是可以从 C++ 调用该 shell 命令,这就是我会做的。但是看看系统是否提供了一个 c++ 实用程序会很有趣。
  • 目前,我使用的是openSSL to read the serial number/subject name,我的证书是read from a string。我现在唯一需要做的就是从我的可执行文件中提取证书字符串。我想我可以使用 std::system 做一些工作,但我也更愿意为此使用纯 C++ 调用。我不知道 macOS 可执行文件上的 fopen 是否可以读取/提取证书。

标签: c++ macos code-signing


【解决方案1】:

这个答案目前可能不是最佳的,需要大量重构,特别是因为我不是 macOS 开发人员,所以我混合了太多 c/c++/objective-c。

请随意编辑这段代码,特别是如果有内存泄漏,我不知道我有什么 CFRelease。

因此,基于不同的来源,我制定了一个解决方案,以编程方式从 macOS 捆绑包/应用程序/可执行文件中提取证书的主题公用名 (CN) 和序列号。以下是我的代码基于的来源:

代码如下:

#include <Foundation/Foundation.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>

#include <openssl/bio.h>
#include <openssl/x509.h>
#include <openssl/pem.h>

int main(int argc, const char * argv[]) {    

    NSURL* url = [NSURL URLWithString:@"/Path/To/Your/Codesign/MyApp.app"];
    CFURLRef path = (__bridge CFURLRef)url;

    SecStaticCodeRef codeRef;
    SecStaticCodeCreateWithPath(path, kSecCSDefaultFlags, &codeRef);      

    SecCSFlags flags = kSecCSInternalInformation
    | kSecCSSigningInformation
    | kSecCSRequirementInformation
    | kSecCSInternalInformation;

    CFDictionaryRef api;
    SecCodeCopySigningInformation(codeRef, flags, &api);

    CFArrayRef certChain = (CFArrayRef)CFDictionaryGetValue(api, kSecCodeInfoCertificates);

    // Get the first certificate from the .app 
    // use the CFIndex count = CFArrayGetCount(certChain); 
    // If you want to process all certificates in a loop (same to codesign source code).
    SecCertificateRef cert = SecCertificateRef(CFArrayGetValueAtIndex(certChain, 0));
    CFDataRef der = SecCertificateCopyData(cert);

    // Use solution from the example or using NSData*.
    //const unsigned char* data = CFDataGetBytePtr(der);    
    //int len = CFDataGetLength(der);
    NSData* data = (__bridge NSData*)der;    

    BIO* bio = BIO_new_mem_buf((void *)[data bytes], (int)[data length]);
    X509* certssl = NULL;
    X509_NAME* subName = NULL;
    X509_NAME_ENTRY* entry = NULL;
    unsigned char* subjectStr;    

    // Read certificate from the BIO 
    // Note that SecCertificateRef is in DER format
    if ( !( certssl = d2i_X509_bio(bio, NULL)))
        return -1;    

    // Get Subject common name (CN)
    if( !( subName= X509_get_subject_name(certssl)))
        return -1;   

    if( !( entry = X509_NAME_get_entry(subName, X509_NAME_get_index_by_NID(subName, NID_commonName, -1))))
        return -1;   

    ASN1_STRING_to_UTF8(&subjectStr, X509_NAME_ENTRY_get_data(entry));    

    // Extract the certificate's serial number.
    ASN1_INTEGER* asn1_serial = X509_get_serialNumber(certssl);
    if (asn1_serial == NULL)
        return -1;    

    // Convert serial number into a char buffer.
    BIGNUM* bnser = ASN1_INTEGER_to_BN(asn1_serial, NULL);
    char* serialStr = BN_bn2hex(bnser);    

    X509_free(certssl);
    BIO_free_all(bio);
    return 0;
}

【讨论】:

  • 您在为 bio 和 certssl 释放内存之前返回,请使用带有自定义删除器的唯一 ptr
猜你喜欢
  • 2012-10-09
  • 2016-05-20
  • 2010-11-04
  • 1970-01-01
  • 1970-01-01
  • 2010-12-21
  • 2020-11-05
  • 1970-01-01
  • 2011-09-24
相关资源
最近更新 更多