Skip to content

Instantly share code, notes, and snippets.

@kurash
Created October 16, 2019 13:05
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kurash/57e18d6e6e98f397f42086194b7b67bd to your computer and use it in GitHub Desktop.
Save kurash/57e18d6e6e98f397f42086194b7b67bd to your computer and use it in GitHub Desktop.
Add RSA signature to OSX packages (pkg)
/*
(c) 2012-2016 Sassafras Software Inc.
Provided "as is" under the terms of the MIT license, no warranty, use at your own risk
*/
/*
to build:
cc pkgresign.c -framework Security -framework CoreFoundation -lxar -o pkgresign
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#include <xar/xar.h>
static CFTypeRef sign_pkg (const char *path, off_t *offset);
static CFTypeRef sign_xar (xar_signature_t s);
static SecKeyRef sign_findkey (xar_signature_t s);
static SecCertificateRef sign_cert (xar_signature_t s);
int
main (int argc, char **argv)
{
CFTypeRef result;
off_t offset;
int fd;
if (argc < 2) {
fprintf(stderr, "usage: pkgresign installer.pkg\n");
return(1);
}
result = sign_pkg(argv[1], &offset);
if (result == NULL) {
fprintf(stderr, "signature failed\n");
return(1);
}
if (CFGetTypeID(result) == CFBooleanGetTypeID())
return(0);
if (CFGetTypeID(result) == CFStringGetTypeID()
|| CFGetTypeID(result) == CFErrorGetTypeID())
{
fprintf(stderr, "signature failed:\n");
CFShow(result);
return(1);
}
fd = open(argv[1], O_RDWR);
if (fd == -1) {
fprintf(stderr, "can't open pkg file for writing\n");
return(1);
}
if (lseek(fd, offset, SEEK_SET) == -1) {
fprintf(stderr, "can't seek to signature offset\n");
return(1);
}
if (write(fd, CFDataGetBytePtr(result), CFDataGetLength(result)) == -1) {
fprintf(stderr, "failed to write signature\n");
return(1);
}
close(fd);
return(0);
}
CFTypeRef
sign_pkg (const char *path, off_t *offset)
{
xar_t x;
xar_signature_t s;
CFDataRef result;
x = xar_open(path, READ);
if (x == NULL)
return(CFSTR("can't open pkg file for reading"));
s = xar_signature_first(x);
if (s == NULL)
return(CFSTR("no signatures present"));
if (offset != NULL) {
if (xar_signature_copy_signed_data(s, NULL, NULL, NULL, NULL, offset))
return(CFSTR("signature offset can't be loaded"));
*offset += xar_get_heap_offset(x);
}
result = sign_xar(s);
xar_close(x);
return(result);
}
CFTypeRef
sign_xar (xar_signature_t s)
{
uint8_t *digest, *signed_data;
uint32_t length, signed_length;
CFDataRef data;
SecKeyRef pvtkey;
SecTransformRef sign;
CFErrorRef error;
CFTypeRef result;
if (xar_signature_copy_signed_data(s, &digest, &length, &signed_data, &signed_length, NULL))
return(CFSTR("signature can't be loaded"));
pvtkey = sign_findkey(s);
if (pvtkey == NULL) {
result = CFSTR("private key not available");
} else {
sign = SecSignTransformCreate(pvtkey, &error);
if (sign == NULL) {
result = CFSTR("can't create transform");
} else {
data = CFDataCreate(NULL, digest, length);
if (!SecTransformSetAttribute(sign, kSecTransformInputAttributeName, data, &error)) {
CFRelease(data);
if (error)
result = error;
else
result = CFSTR("can't sign data");
} else {
CFRelease(data);
if (!SecTransformSetAttribute(sign, kSecInputIsAttributeName, kSecInputIsDigest, &error)) {
if (error)
result = error;
else
result = CFSTR("can't sign data");
} else {
result = SecTransformExecute(sign, &error);
if (result == NULL) {
if (error)
result = error;
else
result = CFSTR("can't sign data");
} else if (CFDataGetLength(result) != signed_length) {
CFRelease(result);
result = NULL;
} else if (memcmp(CFDataGetBytePtr(result), signed_data, signed_length) == 0) {
CFRelease(result);
result = kCFBooleanTrue;
}
}
}
CFRelease(sign);
}
CFRelease(pvtkey);
}
free(digest);
free(signed_data);
return(result);
}
SecKeyRef
sign_findkey (xar_signature_t s)
{
SecCertificateRef cert;
SecIdentityRef identity;
SecKeyRef key;
OSStatus err;
key = NULL;
cert = sign_cert(s);
if (cert != NULL) {
err = SecIdentityCreateWithCertificate(NULL, cert, &identity);
if (err == 0) {
err = SecIdentityCopyPrivateKey(identity, &key);
CFRelease(identity);
}
CFRelease(cert);
}
return(key);
}
SecCertificateRef
sign_cert (xar_signature_t s)
{
int32_t i, count;
uint32_t cert_len;
const uint8_t *cert_data;
CFDataRef data;
SecCertificateRef cert;
count = xar_signature_get_x509certificate_count(s);
if (count <= 0)
return(NULL);
for (i = 0; i < count; i++) {
if (xar_signature_get_x509certificate_data(s, i, &cert_data, &cert_len) != 0
|| cert_len == 0)
{
break;
}
data = CFDataCreate(NULL, cert_data, cert_len);
if (data == NULL)
break;
cert = SecCertificateCreateWithData(NULL, data);
CFRelease(data);
if (cert != NULL)
return(cert);
}
return(NULL);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment