xar++.cpp
1 /* 2 * Copyright (c) 2011-2012 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 // 25 // xar++ - interface to XAR-format archive files 26 // 27 #include "xar++.h" 28 #include "notarization.h" 29 #include <security_utilities/cfutilities.h> 30 #include <Security/Security.h> 31 32 33 namespace Security { 34 namespace CodeSigning { 35 36 37 Xar::Xar(const char *path) 38 { 39 mXar = 0; 40 mSigCMS = 0; 41 mSigClassic = 0; 42 if (path) 43 open(path); 44 } 45 46 void Xar::open(const char *path) 47 { 48 if ((mXar = ::xar_open(path, READ)) == NULL) 49 return; 50 51 mPath = std::string(path); 52 53 xar_signature_t sig = ::xar_signature_first(mXar); 54 // read signatures until we find a CMS signature 55 while (sig && mSigCMS == NULL) { 56 const char *type = ::xar_signature_type(sig); 57 if (strcmp(type, "CMS") == 0) { 58 mSigCMS = sig; 59 } else if (strcmp(type, "RSA") == 0) { 60 mSigClassic = sig; 61 } 62 sig = ::xar_signature_next(sig); 63 } 64 } 65 66 Xar::~Xar() 67 { 68 if (mXar) 69 ::xar_close(mXar); 70 } 71 72 static CFArrayRef copyCertChainFromSignature(xar_signature_t sig) 73 { 74 unsigned count = xar_signature_get_x509certificate_count(sig); 75 CFRef<CFMutableArrayRef> certs = makeCFMutableArray(0); 76 for (unsigned ix = 0; ix < count; ix++) { 77 const uint8_t *data; 78 uint32_t length; 79 if (xar_signature_get_x509certificate_data(sig, ix, &data, &length) == 0) { 80 CFTempData cdata(data, length); 81 CFRef<SecCertificateRef> cert = SecCertificateCreateWithData(NULL, cdata); 82 CFArrayAppendValue(certs, cert.get()); 83 } 84 } 85 return certs.yield(); 86 } 87 88 CFArrayRef Xar::copyCertChain() 89 { 90 if (mSigCMS) 91 return copyCertChainFromSignature(mSigCMS); 92 else if (mSigClassic) 93 return copyCertChainFromSignature(mSigClassic); 94 return NULL; 95 } 96 97 void Xar::registerStapledNotarization() 98 { 99 registerStapledTicketInPackage(mPath); 100 } 101 102 CFDataRef Xar::createPackageChecksum() 103 { 104 xar_signature_t sig = NULL; 105 106 // Always prefer a CMS signature to a class signature and return early 107 // if no appropriate signature has been found. 108 if (mSigCMS) { 109 sig = mSigCMS; 110 } else if (mSigClassic) { 111 sig = mSigClassic; 112 } else { 113 return NULL; 114 } 115 116 // Extract the signed data from the xar, which is actually just the checksum 117 // we use as an identifying hash. 118 uint8_t *data = NULL; 119 uint32_t length; 120 if (xar_signature_copy_signed_data(sig, &data, &length, NULL, NULL, NULL) != 0) { 121 secerror("Unable to extract package hash for package: %s", mPath.c_str()); 122 return NULL; 123 } 124 125 // xar_signature_copy_signed_data returns malloc'd data that can be used without copying 126 // but must be free'd properly later. 127 return makeCFDataMalloc(data, length); 128 } 129 130 SecCSDigestAlgorithm Xar::checksumDigestAlgorithm() 131 { 132 int32_t error = 0; 133 const char* value = NULL; 134 unsigned long size = 0; 135 136 if (mXar == NULL) { 137 secerror("Evaluating checksum digest on bad xar: %s", mPath.c_str()); 138 return kSecCodeSignatureNoHash; 139 } 140 141 error = xar_prop_get((xar_file_t)mXar, "checksum/size", &value); 142 if (error == -1) { 143 secerror("Unable to extract package checksum size: %s", mPath.c_str()); 144 return kSecCodeSignatureNoHash; 145 } 146 147 size = strtoul(value, NULL, 10); 148 switch (size) { 149 case CC_SHA1_DIGEST_LENGTH: 150 return kSecCodeSignatureHashSHA1; 151 case CC_SHA256_DIGEST_LENGTH: 152 return kSecCodeSignatureHashSHA256; 153 case CC_SHA512_DIGEST_LENGTH: 154 return kSecCodeSignatureHashSHA512; 155 case CC_MD5_DIGEST_LENGTH: 156 default: 157 return kSecCodeSignatureNoHash; 158 } 159 } 160 161 } // end namespace CodeSigning 162 } // end namespace Security