C++ macOS - 以编程方式检索代码签名证书信息
C++ macOS - Programmatically retrieve code sign certificate information
在 Windows,有可能使用 CryptQueryObject.
获得 .exe/.dll 代码签名证书
是否有任何 c++(或 objective-c)替代方法来检索证书的 主题名称 和 序列号已用于在 macOS 上对 .app 进行代码签名?
我在使用 xcode 对我的 .app 进行代码签名时没有问题,当我在终端中时,我能够看到我的代码已使用正确的证书进行签名。
编辑:
我的想法是得到类似这个命令行的东西,但在 C++ 中。
codesign -v --extract-certificates MyApp.app/
| openssl x509 -inform DER -in codesign0 -text
| grep "Serial" -A 1
这个答案目前可能不是最优的,需要大量重构,特别是因为我不是 macOS 开发人员,所以我混合了太多 c/c++/objective-c.
请随时编辑此代码,特别是如果存在内存泄漏,我不知道我有什么 CFRelease。
因此,基于不同的来源,我提出了一个解决方案,以编程方式从 macOS bundle/app/executable 中提取证书的主题通用名称 (CN) 和序列号。这是我的代码基于的来源:
- Apple codesign source code to extract-certificates
- An example of how to read SecCertificateRef data
- An example of how to read certificate from bytes using openSSL
这里是代码:
#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;
}
在 Windows,有可能使用 CryptQueryObject.
获得 .exe/.dll 代码签名证书是否有任何 c++(或 objective-c)替代方法来检索证书的 主题名称 和 序列号已用于在 macOS 上对 .app 进行代码签名?
我在使用 xcode 对我的 .app 进行代码签名时没有问题,当我在终端中时,我能够看到我的代码已使用正确的证书进行签名。
编辑:
我的想法是得到类似这个命令行的东西,但在 C++ 中。
codesign -v --extract-certificates MyApp.app/
| openssl x509 -inform DER -in codesign0 -text
| grep "Serial" -A 1
这个答案目前可能不是最优的,需要大量重构,特别是因为我不是 macOS 开发人员,所以我混合了太多 c/c++/objective-c.
请随时编辑此代码,特别是如果存在内存泄漏,我不知道我有什么 CFRelease。
因此,基于不同的来源,我提出了一个解决方案,以编程方式从 macOS bundle/app/executable 中提取证书的主题通用名称 (CN) 和序列号。这是我的代码基于的来源:
- Apple codesign source code to extract-certificates
- An example of how to read SecCertificateRef data
- An example of how to read certificate from bytes using openSSL
这里是代码:
#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;
}