#include <Security/SecAsn1Types.h>
#include <Security/SecAsn1Coder.h>
#include <security_keychain/KeyItem.h>
+#include <security_utilities/casts.h>
#include <CommonCrypto/CommonKeyDerivation.h>
#include "SecBridge.h"
SecCDSAKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) {
key->key = const_cast<KeyItem *>(reinterpret_cast<const KeyItem *>(keyData));
key->key->initializeWithSecKeyRef(key);
+ key->credentialType = kSecCredentialTypeDefault;
return errSecSuccess;
}
static CFDataRef SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo) {
// First of all, consider x509 format and try to strip SubjPubKey envelope. If it fails, do not panic
// and export data as is.
- DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), CFDataGetLength(pubKeyInfo) }, pubKeyItem;
+ DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), int_cast<CFIndex, DERSize>(CFDataGetLength(pubKeyInfo)) }, pubKeyItem;
DERByte numUnused;
DERSubjPubKeyInfo subjPubKey;
if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs,
static CFDataRef SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm, uint32 keySizeInBits, CFDataRef pubKeyInfo) {
// First check, whether X509 pubkeyinfo is already present. If not, add it according to the key type.
- DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), CFDataGetLength(pubKeyInfo) };
+ DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), int_cast<CFIndex, DERSize>(CFDataGetLength(pubKeyInfo)) };
DERSubjPubKeyInfo subjPubKey;
if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs,
DERSubjPubKeyInfoItemSpecs,
subjPubKey.algId.length = sizeof(oidECsecp256);
} else if (keySizeInBits == 384) {
subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp384);
- subjPubKey.algId.length = sizeof(oidECsecp256);
+ subjPubKey.algId.length = sizeof(oidECsecp384);
} if (keySizeInBits == 521) {
subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp521);
- subjPubKey.algId.length = sizeof(oidECsecp256);
+ subjPubKey.algId.length = sizeof(oidECsecp521);
}
}
DERSize size = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE, &subjPubKey,
CFRef<CFDataRef> privKeyData;
result = SecItemExport(key, kSecFormatOpenSSL, 0, NULL, privKeyData.take());
if (result == errSecSuccess) {
- DERItem keyItem = { (DERByte *)CFDataGetBytePtr(privKeyData), CFDataGetLength(privKeyData) };
+ DERItem keyItem = { (DERByte *)CFDataGetBytePtr(privKeyData), int_cast<CFIndex, DERSize>(CFDataGetLength(privKeyData)) };
DERRSAKeyPair keyPair;
if (DERParseSequence(&keyItem, DERNumRSAKeyPairItemSpecs, DERRSAKeyPairItemSpecs,
&keyPair, sizeof(keyPair)) == DR_Success) {
MacOSError::check(SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take()));
if (header.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY) {
// Convert DER format into x9.63 format, which is expected for exported key.
- DERItem keyItem = { (DERByte *)CFDataGetBytePtr(keyData), CFDataGetLength(keyData) };
+ DERItem keyItem = { (DERByte *)CFDataGetBytePtr(keyData), int_cast<CFIndex, DERSize>(CFDataGetLength(keyData)) };
DERECPrivateKey privateKey;
DERECPrivateKeyPublicKey privateKeyPublicKey;
DERByte numUnused;
Item publicKey = key->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY, uniqueId);
result = reinterpret_cast<SecKeyRef>(publicKey->handle());
}
- } else if (key->publicKey()) {
+ }
+
+ if (result == NULL && key->publicKey()) {
KeyItem *publicKey = new KeyItem(key->publicKey());
result = reinterpret_cast<SecKeyRef>(publicKey->handle());
}
static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm,
CSSM_ALGORITHMS &baseAlgorithm, CSSM_ALGORITHMS &secondaryAlgorithm,
- CSSM_ALGORITHMS &paddingAlgorithm) {
+ CSSM_ALGORITHMS &paddingAlgorithm, CFIndex &inputSizeLimit) {
KeyItem *keyItem = key->key;
CSSM_KEYCLASS keyClass = keyItem->key()->header().keyClass();
baseAlgorithm = keyItem->key()->header().algorithm();
if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureRaw)) {
secondaryAlgorithm = CSSM_ALGID_NONE;
paddingAlgorithm = CSSM_PADDING_NONE;
+ inputSizeLimit = 0;
} else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw)) {
secondaryAlgorithm = CSSM_ALGID_NONE;
paddingAlgorithm = CSSM_PADDING_PKCS1;
+ inputSizeLimit = -11;
} else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1)) {
secondaryAlgorithm = CSSM_ALGID_SHA1;
paddingAlgorithm = CSSM_PADDING_PKCS1;
+ inputSizeLimit = 20;
} else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224)) {
secondaryAlgorithm = CSSM_ALGID_SHA224;
paddingAlgorithm = CSSM_PADDING_PKCS1;
+ inputSizeLimit = 224 / 8;
} else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256)) {
secondaryAlgorithm = CSSM_ALGID_SHA256;
paddingAlgorithm = CSSM_PADDING_PKCS1;
+ inputSizeLimit = 256 / 8;
} else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384)) {
secondaryAlgorithm = CSSM_ALGID_SHA384;
paddingAlgorithm = CSSM_PADDING_PKCS1;
+ inputSizeLimit = 384 / 8;
} else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512)) {
secondaryAlgorithm = CSSM_ALGID_SHA512;
paddingAlgorithm = CSSM_PADDING_PKCS1;
+ inputSizeLimit = 512 / 8;
} else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5)) {
secondaryAlgorithm = CSSM_ALGID_MD5;
paddingAlgorithm = CSSM_PADDING_PKCS1;
+ inputSizeLimit = 16;
} else {
return NULL;
}
if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) {
secondaryAlgorithm = CSSM_ALGID_NONE;
paddingAlgorithm = CSSM_PADDING_NONE;
+ inputSizeLimit = 0;
} else if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionPKCS1)) {
secondaryAlgorithm = CSSM_ALGID_NONE;
paddingAlgorithm = CSSM_PADDING_PKCS1;
+ inputSizeLimit = operation == kSecKeyOperationTypeEncrypt ? -11 : 0;
} else {
return NULL;
}
CFArrayRef allAlgorithms, SecKeyOperationMode mode,
CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
BEGIN_SECKEYAPI(CFTypeRef, kCFNull)
+ CFIndex inputSizeLimit = 0;
CSSM_ALGORITHMS baseAlgorithm, secondaryAlgorithm, paddingAlgorithm;
- KeyItem *keyItem = SecCDSAKeyPrepareParameters(key, operation, algorithm, baseAlgorithm, secondaryAlgorithm, paddingAlgorithm);
+ KeyItem *keyItem = SecCDSAKeyPrepareParameters(key, operation, algorithm, baseAlgorithm, secondaryAlgorithm, paddingAlgorithm, inputSizeLimit);
if (keyItem == NULL) {
// Operation/algorithm/key combination is not supported.
return kCFNull;
} else if (mode == kSecKeyOperationModeCheckIfSupported) {
// Operation is supported and caller wants to just know that.
return kCFBooleanTrue;
+ } else if (baseAlgorithm == CSSM_ALGID_RSA) {
+ if (inputSizeLimit <= 0) {
+ inputSizeLimit += SecCDSAKeyGetBlockSize(key);
+ }
+ if (CFDataGetLength((CFDataRef)in1) > inputSizeLimit) {
+ MacOSError::throwMe(errSecParam);
+ }
}
switch (operation) {
case kSecKeyOperationTypeSign: {
CssmClient::Sign signContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm);
signContext.key(keyItem->key());
- signContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault));
+ signContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, key->credentialType));
signContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm);
CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
CssmAutoData signature(signContext.allocator());
case kSecKeyOperationTypeVerify: {
CssmClient::Verify verifyContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm);
verifyContext.key(keyItem->key());
- verifyContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ANY, kSecCredentialTypeDefault));
+ verifyContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ANY, key->credentialType));
verifyContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm);
CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
verifyContext.verify(CssmData(CFDataRef(input)), CssmData(CFRef<CFDataRef>::check(in2, errSecParam)));
CssmClient::Encrypt encryptContext(keyItem->csp(), baseAlgorithm);
encryptContext.key(keyItem->key());
encryptContext.padding(paddingAlgorithm);
- encryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT, kSecCredentialTypeDefault));
+ encryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT, key->credentialType));
CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
CssmAutoData output(encryptContext.allocator()), remainingData(encryptContext.allocator());
size_t length = encryptContext.encrypt(CssmData(CFDataRef(input)), output.get(), remainingData.get());
CssmClient::Decrypt decryptContext(keyItem->csp(), baseAlgorithm);
decryptContext.key(keyItem->key());
decryptContext.padding(paddingAlgorithm);
- decryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT, kSecCredentialTypeDefault));
+ decryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT, key->credentialType));
CssmAutoData output(decryptContext.allocator()), remainingData(decryptContext.allocator());
size_t length = decryptContext.decrypt(CssmData(CFRef<CFDataRef>::check(in1, errSecParam)),
output.get(), remainingData.get());
END_SECKEYAPI
}
-static Boolean SecCDSAIsEqual(SecKeyRef key1, SecKeyRef key2) {
+static Boolean SecCDSAKeyIsEqual(SecKeyRef key1, SecKeyRef key2) {
CFErrorRef *error;
BEGIN_SECKEYAPI(Boolean, false)
END_SECKEYAPI
}
+static Boolean SecCDSAKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) {
+ BEGIN_SECKEYAPI(Boolean, false)
+
+ if (CFEqual(name, kSecUseAuthenticationUI)) {
+ key->credentialType = CFEqual(value, kSecUseAuthenticationUIAllow) ? kSecCredentialTypeDefault : kSecCredentialTypeNoUI;
+ result = true;
+ } else {
+ result = SecError(errSecUnimplemented, error, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name);
+ }
+
+ END_SECKEYAPI
+}
+
const SecKeyDescriptor kSecCDSAKeyDescriptor = {
.version = kSecKeyDescriptorVersion,
.name = "CDSAKey",
.copyExternalRepresentation = SecCDSAKeyCopyExternalRepresentation,
.copyPublicKey = SecCDSAKeyCopyPublicKey,
.copyOperationResult = SecCDSAKeyCopyOperationResult,
- .isEqual = SecCDSAIsEqual,
+ .isEqual = SecCDSAKeyIsEqual,
+ .setParameter = SecCDSAKeySetParameter,
};
namespace Security {
} else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA512)) {
algorithm = kCCPRFHmacAlgSHA512;
} else {
- *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL);
+ if(error) {
+ *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL);
+ }
goto errOut;
}
retval = SecKeyCreateFromData(parameters, keyData, error);
CFRelease(keyData);
} else {
- *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
+ if(error) {
+ *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
+ }
}
errOut:
CFDataRef
SecKeyWrapSymmetric(SecKeyRef keyToWrap, SecKeyRef wrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
{
- *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
+ if(error) {
+ *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
+ }
return NULL;
}
SecKeyRef
SecKeyUnwrapSymmetric(CFDataRef *keyToUnwrap, SecKeyRef unwrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
{
- *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
+ if(error) {
+ *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
+ }
return NULL;
}