Exemplo n.º 1
1
extern "C" PAL_X509ContentType AppleCryptoNative_X509GetContentType(uint8_t* pbData, int32_t cbData)
{
    if (pbData == nullptr || cbData < 0)
        return PAL_X509Unknown;

    CFDataRef cfData = CFDataCreateWithBytesNoCopy(nullptr, pbData, cbData, kCFAllocatorNull);

    if (cfData == nullptr)
        return PAL_X509Unknown;

    // The sniffing order is:
    // * X509 DER
    // * PKCS7 PEM/DER
    // * PKCS12 DER (or PEM if Apple has non-standard support for that)
    // * X509 PEM (or DER, but that already matched)
    //
    // If the X509 PEM check is done first SecItemImport will erroneously match
    // some PKCS#7 blobs and say they were certificates.
    //
    // Likewise, if the X509 DER check isn't done first, Apple will report it as
    // being a PKCS#7.
    SecCertificateRef certref = SecCertificateCreateWithData(nullptr, cfData);

    if (certref != nullptr)
    {
        CFRelease(certref);
        return PAL_Certificate;
    }

    SecExternalFormat dataFormat = kSecFormatPKCS7;
    SecExternalFormat actualFormat = dataFormat;
    SecExternalItemType itemType = kSecItemTypeAggregate;
    SecExternalItemType actualType = itemType;

    OSStatus osStatus = SecItemImport(cfData, nullptr, &actualFormat, &actualType, 0, nullptr, nullptr, nullptr);

    if (osStatus == noErr)
    {
        if (actualType == itemType && actualFormat == dataFormat)
        {
            return PAL_Pkcs7;
        }
    }

    dataFormat = kSecFormatPKCS12;
    actualFormat = dataFormat;
    itemType = kSecItemTypeAggregate;
    actualType = itemType;

    osStatus = SecItemImport(cfData, nullptr, &actualFormat, &actualType, 0, nullptr, nullptr, nullptr);

    if (osStatus == errSecPassphraseRequired)
    {
        dataFormat = kSecFormatPKCS12;
        actualFormat = dataFormat;
        itemType = kSecItemTypeAggregate;
        actualType = itemType;

        SecItemImportExportKeyParameters importParams = {};
        importParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
        importParams.passphrase = CFSTR("");

        osStatus = SecItemImport(cfData, nullptr, &actualFormat, &actualType, 0, &importParams, nullptr, nullptr);

        CFRelease(importParams.passphrase);
        importParams.passphrase = nullptr;
    }

    if (osStatus == noErr || osStatus == errSecPkcs12VerifyFailure)
    {
        if (actualType == itemType && actualFormat == dataFormat)
        {
            return PAL_Pkcs12;
        }
    }

    dataFormat = kSecFormatX509Cert;
    actualFormat = dataFormat;
    itemType = kSecItemTypeCertificate;
    actualType = itemType;

    osStatus = SecItemImport(cfData, nullptr, &actualFormat, &actualType, 0, nullptr, nullptr, nullptr);

    if (osStatus == noErr)
    {
        if (actualType == itemType && actualFormat == dataFormat)
        {
            return PAL_Certificate;
        }
    }

    return PAL_X509Unknown;
}
Exemplo n.º 2
0
static int import_pem(URLContext *h, char *path, CFArrayRef *array)
{
    AVIOContext *s = NULL;
    CFDataRef data = NULL;
    int64_t ret = 0;
    char *buf = NULL;
    SecExternalFormat format = kSecFormatPEMSequence;
    SecExternalFormat type = kSecItemTypeAggregate;
    CFStringRef pathStr = CFStringCreateWithCString(NULL, path, 0x08000100);
    if (!pathStr) {
        ret = AVERROR(ENOMEM);
        goto end;
    }

    if ((ret = ffio_open_whitelist(&s, path, AVIO_FLAG_READ,
                                   &h->interrupt_callback, NULL,
                                   h->protocol_whitelist, h->protocol_blacklist)) < 0)
        goto end;

    if ((ret = avio_size(s)) < 0)
        goto end;

    if (ret == 0) {
        ret = AVERROR_INVALIDDATA;
        goto end;
    }

    if (!(buf = av_malloc(ret))) {
        ret = AVERROR(ENOMEM);
        goto end;
    }

    if ((ret = avio_read(s, buf, ret)) < 0)
        goto end;

    data = CFDataCreate(kCFAllocatorDefault, buf, ret);

    if (SecItemImport(data, pathStr, &format, &type,
                      0, NULL, NULL, array) != noErr || !array) {
        ret = AVERROR_UNKNOWN;
        goto end;
    }

    if (CFArrayGetCount(*array) == 0) {
        ret = AVERROR_INVALIDDATA;
        goto end;
    }

end:
    av_free(buf);
    if (pathStr)
        CFRelease(pathStr);
    if (data)
        CFRelease(data);
    if (s)
        avio_close(s);
    return ret;
}
Exemplo n.º 3
0
static OSStatus AddKeyToKeychain(SecKeyRef privateKey, SecKeychainRef targetKeychain)
{
    // This is quite similar to pal_seckey's ExportImportKey, but
    // a) is used to put something INTO a keychain, instead of to take it out.
    // b) Doesn't assume that the input should be CFRelease()d and overwritten.
    // c) Doesn't return/emit the imported key reference.
    // d) Works on private keys.
    SecExternalFormat dataFormat = kSecFormatWrappedPKCS8;
    CFDataRef exportData = nullptr;

    SecItemImportExportKeyParameters keyParams = {};
    keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
    keyParams.passphrase = CFSTR("ExportImportPassphrase");

    OSStatus status = SecItemExport(privateKey, dataFormat, 0, &keyParams, &exportData);

    SecExternalFormat actualFormat = dataFormat;
    SecExternalItemType actualType = kSecItemTypePrivateKey;
    CFArrayRef outItems = nullptr;

    if (status == noErr)
    {
        status =
            SecItemImport(exportData, nullptr, &actualFormat, &actualType, 0, &keyParams, targetKeychain, &outItems);
    }

    if (exportData != nullptr)
        CFRelease(exportData);

    CFRelease(keyParams.passphrase);
    keyParams.passphrase = nullptr;

    if (outItems != nullptr)
        CFRelease(outItems);

    return status;
}
Exemplo n.º 4
0
static int32_t ReadX509(uint8_t* pbData,
                        int32_t cbData,
                        PAL_X509ContentType contentType,
                        CFStringRef cfPfxPassphrase,
                        SecKeychainRef keychain,
                        bool exportable,
                        SecCertificateRef* pCertOut,
                        SecIdentityRef* pIdentityOut,
                        CFArrayRef* pCollectionOut,
                        int32_t* pOSStatus)
{
    assert(pbData != nullptr);
    assert(cbData >= 0);
    assert((pCertOut == nullptr) == (pIdentityOut == nullptr));
    assert((pCertOut == nullptr) != (pCollectionOut == nullptr));

    SecExternalFormat dataFormat;
    SecExternalItemType itemType;
    int32_t ret = 0;
    CFArrayRef outItems = nullptr;
    CFMutableArrayRef keyAttributes = nullptr;
    SecKeychainRef importKeychain = nullptr;

    SecItemImportExportKeyParameters importParams = {};
    importParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;

    if (contentType == PAL_Certificate)
    {
        dataFormat = kSecFormatX509Cert;
        itemType = kSecItemTypeCertificate;
    }
    else if (contentType == PAL_Pkcs7)
    {
        dataFormat = kSecFormatPKCS7;
        itemType = kSecItemTypeAggregate;
    }
    else if (contentType == PAL_Pkcs12)
    {
        dataFormat = kSecFormatPKCS12;
        itemType = kSecItemTypeAggregate;

        importParams.passphrase = cfPfxPassphrase;
        importKeychain = keychain;

        if (keychain == nullptr)
        {
            return kErrorBadInput;
        }

        // if keyAttributes is nullptr then it uses SENSITIVE | EXTRACTABLE
        // so if !exportable was requested, assert SENSITIVE.
        if (!exportable)
        {
            keyAttributes = CFArrayCreateMutable(nullptr, 9, &kCFTypeArrayCallBacks);

            if (keyAttributes == nullptr)
            {
                *pOSStatus = errSecAllocate;
                return 0;
            }

            int32_t sensitiveValue = CSSM_KEYATTR_SENSITIVE;
            CFNumberRef sensitive = CFNumberCreate(nullptr, kCFNumberSInt32Type, &sensitiveValue);

            if (sensitive == nullptr)
            {
                CFRelease(keyAttributes);
                *pOSStatus = errSecAllocate;
                return 0;
            }

            CFArrayAppendValue(keyAttributes, sensitive);
            CFRelease(sensitive);

            importParams.keyAttributes = keyAttributes;
        }
    }
    else
    {
        *pOSStatus = errSecUnknownFormat;
        return 0;
    }

    CFDataRef cfData = CFDataCreateWithBytesNoCopy(nullptr, pbData, cbData, kCFAllocatorNull);

    if (cfData == nullptr)
    {
        *pOSStatus = errSecAllocate;
    }

    if (*pOSStatus == noErr)
    {
        *pOSStatus = SecItemImport(cfData, nullptr, &dataFormat, &itemType, 0, &importParams, keychain, &outItems);
    }

    if (contentType == PAL_Pkcs12 && *pOSStatus == errSecPassphraseRequired && cfPfxPassphrase == nullptr)
    {
        if (outItems != nullptr)
        {
            CFRelease(outItems);
            outItems = nullptr;
        }

        // Try again with the empty string passphrase.
        importParams.passphrase = CFSTR("");

        *pOSStatus = SecItemImport(cfData, nullptr, &dataFormat, &itemType, 0, &importParams, keychain, &outItems);

        CFRelease(importParams.passphrase);
        importParams.passphrase = nullptr;
    }

    if (*pOSStatus == noErr)
    {
        if (pCollectionOut != nullptr)
        {
            CFRetain(outItems);
            *pCollectionOut = outItems;
            ret = 1;
        }
        else
        {
            ret = ProcessCertificateTypeReturn(outItems, pCertOut, pIdentityOut);
        }
    }

    if (keyAttributes != nullptr)
    {
        CFRelease(keyAttributes);
    }

    if (outItems != nullptr)
    {
        // In the event this is returned via pCollectionOut it was already
        // CFRetain()ed, so always CFRelease here.
        CFRelease(outItems);
    }

    CFRelease(cfData);
    return ret;
}
bool
_mongoc_secure_transport_import_pem (const char *filename, const char *passphrase, CFArrayRef *items, SecExternalItemType *type)
{
   SecExternalFormat format = kSecFormatPEMSequence;
   SecItemImportExportKeyParameters params;
   SecTransformRef sec_transform;
   CFReadStreamRef read_stream;
   CFDataRef dataref;
   CFErrorRef error;
   CFURLRef url;
   OSStatus res;


   if (!filename) {
      MONGOC_INFO ("%s", "No certificate provided");
      return false;
   }

   params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
   params.flags = 0;
   params.passphrase = NULL;
   params.alertTitle = NULL;
   params.alertPrompt = NULL;
   params.accessRef = NULL;
   params.keyUsage = NULL;
   params.keyAttributes = NULL;

   if (passphrase) {
      params.passphrase = CFStringCreateWithCString (kCFAllocatorDefault, passphrase, kCFStringEncodingUTF8);
   }

   url = CFURLCreateFromFileSystemRepresentation (kCFAllocatorDefault, (const UInt8 *)filename, strlen (filename), false);
   read_stream = CFReadStreamCreateWithFile (kCFAllocatorDefault, url);
   sec_transform = SecTransformCreateReadTransformWithReadStream (read_stream);
   dataref = SecTransformExecute (sec_transform, &error);


   if (error) {
      CFStringRef str = CFErrorCopyDescription (error);
      MONGOC_ERROR ("Failed importing PEM '%s': %s", filename, CFStringGetCStringPtr (str, CFStringGetFastestEncoding(str)));
      CFRelease (str);
      CFRelease (sec_transform);
      CFRelease (read_stream);
      CFRelease (url);

      if (passphrase) {
         CFRelease (params.passphrase);
      }
      return false;
   }

   res = SecItemImport (dataref, CFSTR(".pem"), &format, type, 0, &params, NULL, items);
   CFRelease (dataref);
   CFRelease (sec_transform);
   CFRelease (read_stream);
   CFRelease (url);

   if (passphrase) {
      CFRelease (params.passphrase);
   }
   if (res) {
      MONGOC_ERROR ("Failed importing PEM '%s' (code: %d)", filename, res);
      return false;
   }

   return true;
}
Exemplo n.º 6
0
Boolean APSetKey(CFStringRef key)
{
    hash = CFSTR("");
    blacklist = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
    
    CFMutableStringRef mutableKey = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, key);
    CFStringRef preparedKey = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, key);
    CFLocaleRef currentLocale = CFLocaleCopyCurrent();
    CFStringLowercase(mutableKey, currentLocale);
    CFRelease(currentLocale);
    
    if (CFStringHasPrefix(mutableKey, CFSTR("0x")) && CFStringGetLength(mutableKey) > 2)
    {
        CFStringDelete(mutableKey, CFRangeMake(0, 2));
    }
    if (CFStringGetLength(mutableKey) == 1024/8*2)
    {
        CFRelease(preparedKey);
        preparedKey = APPEMKeyCreateFromHexKey(mutableKey);
    }
    CFRelease(mutableKey);
    
    
    SecItemImportExportKeyParameters params = {0};
    params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
    params.flags = kSecKeyNoAccessControl;
    SecExternalItemType itemType = kSecItemTypePublicKey;
    SecExternalFormat externalFormat = kSecFormatPEMSequence;
    CFArrayRef tempArray = NULL;
    OSStatus oserr = noErr;
    
    // Set the key as extractable. Looking through the source code in SecImportExportUtils.cpp
    // it looks like this isn't handled, yet it seems to be documented to me. One day the code
    // may catch up, so I'm leaving this here to show the intention.
    CFNumberRef attributeFlags[1];
    uint32 flag0value = CSSM_KEYATTR_EXTRACTABLE;
    CFNumberRef flag0 = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &flag0value);
    attributeFlags[0] = flag0;
    CFArrayRef keyAttributes = CFArrayCreate(kCFAllocatorDefault, (const void **)attributeFlags, 1, &kCFTypeArrayCallBacks);
    CFRelease(flag0);
    params.keyAttributes = keyAttributes;
    
    CFDataRef keyData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, preparedKey, kCFStringEncodingUTF8, 0);
    CFRelease(preparedKey);
    
    oserr = SecItemImport(keyData,
                          NULL,
                          &externalFormat,
                          &itemType,
                          0,
                          &params,
                          NULL,
                          &tempArray);
    CFRelease(keyAttributes);
    CFRelease(keyData);
    
    if (oserr != noErr) {
        CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Unable to import key. Error %d"), oserr);
        CFShow(errorString);
        CFRelease(errorString);
        return FALSE;
    }
    
    publicKeyRef = (SecKeyRef)CFArrayGetValueAtIndex(tempArray, 0);
    CFRetain(publicKeyRef);
    CFRelease(tempArray);
    
    return TRUE;
}