OSStatus
SecPasswordAction(SecPasswordRef itemRef, CFTypeRef message, UInt32 flags, UInt32 *length, const void **data)
{
    BEGIN_SECAPI

    Password passwordRef = PasswordImpl::required(itemRef);
    
    void *passwordData = NULL;
    UInt32 passwordLength = 0;
	bool gotPassword = false;

    // no flags has no meaning, and there is no apparent default
    assert( flags );
    
    // fail can only be combined with get or new
    assert( (flags & kSecPasswordFail) ? ((flags & kSecPasswordGet) || (flags & kSecPasswordNew)) : true );

    // XXX/cs replace this with our CFString->UTF8 conversion
    const char *messageData = NULL;
    auto_array<char> messageBuffer;
    
    if (message && (CFStringGetTypeID() == CFGetTypeID(message)))
    {
        messageData = CFStringGetCStringPtr(static_cast<CFStringRef>(message), kCFStringEncodingUTF8);

        if (messageData == NULL)
        {
            CFIndex maxLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(static_cast<CFStringRef>(message)), kCFStringEncodingUTF8) + 1;

            messageBuffer.allocate(maxLen);
            if (CFStringGetCString(static_cast<CFStringRef>(message), messageBuffer.get(), maxLen, kCFStringEncodingUTF8))
                messageData = messageBuffer.get();
        }
    }
    
    if (passwordRef->useKeychain() && !(flags & kSecPasswordNew) && !(flags & kSecPasswordFail))
    {
            // Pull out data and if it's successful return it
            if (flags & kSecPasswordGet)
            {
            
                // XXX/cs if there are unsaved changes this doesn't work
                //        so doing a Get followed by a Get|Set will do the wrong thing
            
                // check mItem whether it's got data
                if (passwordRef->getData(length, data))
                    return errSecSuccess;
            }
            
            // User might cancel here, immediately return that too (it will be thrown)            
    }

    // If we're still here we're not using the keychain or it wasn't there yet
    
    // Do the authorization call to get the password, unless only kSecPasswordSet is specified)
    if ((flags & kSecPasswordNew) || (flags & kSecPasswordGet))
    {
        AuthorizationRef authRef;
        OSStatus status = AuthorizationCreate(NULL,NULL,0,&authRef);
        if (status != errSecSuccess)
        {
            MacOSError::throwMe(status);
        }
        
        AuthorizationItem right = { NULL, 0, NULL, 0 };
        AuthorizationItemSet rightSet = { 1, &right };
        uint32_t reason, tries;
        bool keychain = 0, addToKeychain = 0;

        if (passwordRef->useKeychain())
        {
            keychain = 1;
            addToKeychain = passwordRef->rememberInKeychain();
        }
		else
		{
            keychain = 0;
            addToKeychain = 0;
		}
        
        // Get|Fail conceivable would have it enabled, but since the effect is that it will get overwritten
        // we'll make the user explicitly do it       
        if (flags & kSecPasswordGet)
            addToKeychain = 0; // turn it off for old items that weren't successfully retrieved from the keychain

        if (flags & kSecPasswordFail) // set up retry to reflect failure
        {
	        tries = 1;
            if (flags & kSecPasswordNew)
                reason = 34; // passphraseUnacceptable = 34 passphrase unacceptable for some other reason
            else
                reason = 21; // invalidPassphrase = 21 passphrase was wrong
        }
        else
		{
			reason = 0;
			tries = 0;
		}

        if (flags & kSecPasswordNew) // pick new passphrase
            right.name = "com.apple.builtin.generic-new-passphrase";
        else
            right.name = "com.apple.builtin.generic-unlock";

        bool showPassword = false;
        
        AuthorizationItem envRights[6] = { { AGENT_HINT_RETRY_REASON, sizeof(reason), &reason, 0 },
                                            { AGENT_HINT_TRIES, sizeof(tries), &tries, 0 },
                                            { AGENT_HINT_CUSTOM_PROMPT, messageData ? strlen(messageData) : 0, const_cast<char*>(messageData), 0 },
                                            { AGENT_HINT_ALLOW_SHOW_PASSWORD, showPassword ? strlen("YES") : strlen("NO"), const_cast<char *>(showPassword ? "YES" : "NO"), 0 },
                                            { AGENT_HINT_SHOW_ADD_TO_KEYCHAIN, keychain ? strlen("YES") : strlen("NO"), const_cast<char *>(keychain ? "YES" : "NO"), 0 },
                                            { AGENT_ADD_TO_KEYCHAIN, addToKeychain ? strlen("YES") : strlen("NO"), const_cast<char *>(addToKeychain ? "YES" : "NO"), 0 } };
                                            
        AuthorizationItemSet envSet = { sizeof(envRights) / sizeof(*envRights), envRights };

	    secdebug("SecPassword", "dialog(%s)%s%s%s.", right.name, tries?" retry":"", keychain?" show-add-keychain":"", addToKeychain?" save-to-keychain":"");

        status = AuthorizationCopyRights(authRef, &rightSet, &envSet, kAuthorizationFlagDefaults|kAuthorizationFlagInteractionAllowed|kAuthorizationFlagExtendRights, NULL);
        
        if (status)
        {
            AuthorizationFree(authRef, 0);
            return status;
        }
        
        // if success pull the data
        AuthorizationItemSet *returnedInfo;
        status = AuthorizationCopyInfo(authRef, NULL, &returnedInfo);
        
        if (status)
        {
            AuthorizationFree(authRef, 0);
            
            return status;
        }
        
        if (returnedInfo && (returnedInfo->count > 0))
        {
            for (uint32_t index = 0; index < returnedInfo->count; index++)
            {
                AuthorizationItem &item = returnedInfo->items[index];
                
                if (!strcmp(AGENT_PASSWORD, item.name))
                {
					gotPassword = true;
                    passwordLength = (UInt32)item.valueLength;

                    if (passwordLength)
                    {
                        Allocator &allocator = Allocator::standard();
                        passwordData = allocator.malloc(passwordLength);
                        if (passwordData)
                            memcpy(passwordData, item.value, passwordLength);
                    }
                    
                    if (length)
                        *length = passwordLength;
                    if (data) 
                        *data = passwordData;
						
					secdebug("SecPassword", "Got password (%u,%p).", (unsigned int)passwordLength, passwordData);
                }
                else if (!strcmp(AGENT_ADD_TO_KEYCHAIN, item.name))
                {
                    bool remember = (item.value && item.valueLength == strlen("YES") && !memcmp("YES", static_cast<char *>(item.value), item.valueLength));
					passwordRef->setRememberInKeychain(remember);
					if (remember)
						secdebug("SecPassword", "User wants to add the password to the Keychain.");
                }
            }
        }
        
        AuthorizationFreeItemSet(returnedInfo);
        AuthorizationFree(authRef, 0);
        
    }

    // If we're still here the use gave us his password, store it if keychain is in use
    if (passwordRef->useKeychain())
    {
        if (passwordRef->rememberInKeychain()) {
            if (gotPassword)
				passwordRef->setData(passwordLength, passwordData);
			if (flags & kSecPasswordSet)
            {
				passwordRef->save();
                gotPassword = true;
            }
		}
    }

    if (!gotPassword)
    {
        return errAuthorizationDenied;
    }
    
    END_SECAPI
}
Beispiel #2
0
//
// Same thing, but obtain a new secret somehow and set it into the common.
//
void KeychainDatabase::establishNewSecrets(const AccessCredentials *creds, SecurityAgent::Reason reason)
{
	list<CssmSample> samples;
	if (creds && creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK, samples)) {
		for (list<CssmSample>::iterator it = samples.begin(); it != samples.end(); it++) {
			TypedList &sample = *it;
			sample.checkProper();
			switch (sample.type()) {
			// interactively prompt the user
			case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT:
                {
				secdebug("KCdb", "%p specified interactive passphrase", this);
				QueryNewPassphrase query(*this, reason);
				StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
				query.inferHints(Server::process());
				CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
                CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive));
				if (query(oldPassphrase, passphrase) == SecurityAgent::noReason) {
					common().setup(NULL, passphrase);
                    change_secret_on_keybag(common(), oldPassphrase.data(), (int)oldPassphrase.length(), passphrase.data(), (int)passphrase.length());
					return;
				}
                }
				break;
			// try to use an explicitly given passphrase
			case CSSM_SAMPLE_TYPE_PASSWORD:
				{
                    secdebug("KCdb", "%p specified explicit passphrase", this);
                    if (sample.length() != 2)
                        CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
                    common().setup(NULL, sample[1]);
                    if (common().isLoginKeychain()) {
                        CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive));
                        list<CssmSample> oldSamples;
                        creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, oldSamples);
                        for (list<CssmSample>::iterator oit = oldSamples.begin(); oit != oldSamples.end(); oit++) {
                            TypedList &tmpList = *oit;
                            tmpList.checkProper();
                            if (tmpList.type() == CSSM_SAMPLE_TYPE_PASSWORD) {
                                if (tmpList.length() == 2) {
                                    oldPassphrase = tmpList[1].data();
                                }
                            }
                        }
                        if (!oldPassphrase.length() && mSecret && mSecret.length()) {
                            oldPassphrase = mSecret;
                        }
                        change_secret_on_keybag(common(), oldPassphrase.data(), (int)oldPassphrase.length(), sample[1].data().data(), (int)sample[1].data().length());
                    }
                    return;
                }
			// try to open with a given master key
			case CSSM_WORDID_SYMMETRIC_KEY:
			case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY:
				secdebug("KCdb", "%p specified explicit master key", this);
				common().setup(NULL, keyFromCreds(sample, 3));
				return;
			// explicitly defeat the default action but don't try anything in particular
			case CSSM_WORDID_CANCELED:
				secdebug("KCdb", "%p defeat default action", this);
				break;
			default:
				// Unknown sub-sample for acquiring new secret.
				// If we wanted to be fascist, we could now do
				//  CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
				// But instead we try to be tolerant and continue on.
				// This DOES however count as an explicit attempt at specifying unlock,
				// so we will no longer try the default case below...
				secdebug("KCdb", "%p unknown sub-sample acquisition (%d) ignored",
					this, sample.type());
				break;
			}
		}
	} else {
		// default action -- interactive (only)
		QueryNewPassphrase query(*this, reason);
		StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
        query.inferHints(Server::process());
		CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
        CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive));
		if (query(oldPassphrase, passphrase) == SecurityAgent::noReason) {
			common().setup(NULL, passphrase);
            change_secret_on_keybag(common(), oldPassphrase.data(), (int)oldPassphrase.length(), passphrase.data(), (int)passphrase.length());
			return;
		}
	}
	
	// out of options - no secret obtained
	CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
}
static void handle_server_response(CFReadStreamRef stream,
    CFStreamEventType type, void *info) {
    asynchttp_t *http = (asynchttp_t *)info;
    if (!http->stream) {
        secerror("Avoiding crash due to CFReadStream invoking us after we called CFReadStreamSetDispatchQueue(stream, NULL) on a different block on our serial queue");
        return;
    }

    switch (type) {
    case kCFStreamEventHasBytesAvailable:
    {
        UInt8 buffer[POST_BUFSIZE];
        CFIndex length;
        do {
#if 1
            length = CFReadStreamRead(stream, buffer, sizeof(buffer));
#else
            const UInt8 *buffer = CFReadStreamGetBuffer(stream, -1, &length);
#endif
            secdebug("http",
                "stream: %@ kCFStreamEventHasBytesAvailable read: %lu bytes",
                stream, length);
            if (length < 0) {
                /* Negative length == error */
                asynchttp_complete(http);
                break;
            } else if (length > 0) {
                //CFHTTPMessageAppendBytes(http->response, buffer, length);
                CFDataAppendBytes(http->data, buffer, length);
            } else {
                /* Read 0 bytes, are we are done or do we wait for
                   kCFStreamEventEndEncountered? */
                asynchttp_complete(http);
                break;
            }
        } while (CFReadStreamHasBytesAvailable(stream));
        break;
    }
    case kCFStreamEventErrorOccurred:
    {
        CFStreamError error = CFReadStreamGetError(stream);

        secdebug("http",
            "stream: %@ kCFStreamEventErrorOccurred domain: %ld error: %ld",
            stream, error.domain, (long) error.error);

        if (error.domain == kCFStreamErrorDomainPOSIX) {
            ocspdErrorLog("CFReadStream posix: %s", strerror(error.error));
        } else if (error.domain == kCFStreamErrorDomainMacOSStatus) {
            ocspdErrorLog("CFReadStream osstatus: %"PRIstatus, error.error);
        } else {
            ocspdErrorLog("CFReadStream domain: %ld error: %"PRIstatus,
                error.domain, error.error);
        }
        asynchttp_complete(http);
        break;
    }
    case kCFStreamEventEndEncountered:
    {
        http->response = (CFHTTPMessageRef)CFReadStreamCopyProperty(
            stream, kCFStreamPropertyHTTPResponseHeader);
        secdebug("http", "stream: %@ kCFStreamEventEndEncountered hdr: %@",
            stream, http->response);
        CFHTTPMessageSetBody(http->response, http->data);
        asynchttp_complete(http);
        break;
    }
    default:
        ocspdErrorLog("handle_server_response unexpected event type: %lu",
            type);
        break;
    }
}
static bool SecPathBuilderGetNext(SecPathBuilderRef builder) {
    /* If we have any candidates left to go return those first. */
    if (CFArrayGetCount(builder->candidatePaths)) {
        SecCertificatePathRef path = (SecCertificatePathRef)
            CFArrayGetValueAtIndex(builder->candidatePaths, 0);
        CFArrayRemoveValueAtIndex(builder->candidatePaths, 0);
        secdebug("trust", "SecPathBuilderGetNext returning candidate %@",
            path);
        SecPVCSetPath(&builder->path, path, NULL);
        builder->state = SecPathBuilderValidatePath;
        return true;
    }

    /* If we are considering rejected chains we check each rejected path
       with SecPathBuilderIsPartial() which checks the signature chain and
       either drops the path if it's not properly signed, add it as a
       candidate if it has a trusted anchor, or adds it as a partial
       to be considered once we finish considering all the rejects. */
    if (builder->considerRejected) {
        CFIndex rejectedIX = CFArrayGetCount(builder->rejectedPaths);
        if (rejectedIX) {
            rejectedIX--;
            SecCertificatePathRef path = (SecCertificatePathRef)
                CFArrayGetValueAtIndex(builder->rejectedPaths, rejectedIX);
            if (SecPathBuilderIsPartial(builder, path)) {
                CFArrayInsertValueAtIndex(builder->partialPaths,
                    ++builder->partialIX, path);
            }
            CFArrayRemoveValueAtIndex(builder->rejectedPaths, rejectedIX);

            /* Keep going until we have moved all rejected partials into
               the regular partials or candidates array. */
            return true;
        }
    }

    /* If builder->partialIX is < 0 we have considered all partial chains
       this block must ensure partialIX >= 0 if execution continues past
       it's end. */
    if (builder->partialIX < 0) {
        CFIndex num_sources = CFArrayGetCount(builder->parentSources);
        if (builder->nextParentSource < num_sources) {
            builder->nextParentSource++;
            secdebug("trust", "broading search to %d/%d sources",
                builder->nextParentSource, num_sources);
        } else {
            /* We've run out of new sources to consider so let's look at
               rejected chains and after that even consider partials
               directly.
               FIXME we might not want to consider partial paths that
               are subsets of other partial paths, or not consider them
               at all if we already have an anchored reject. */
            if (!builder->considerRejected) {
                builder->considerRejected = true;
                secdebug("trust", "considering rejected paths");
            } else if (!builder->considerPartials) {
                builder->considerPartials = true;
                secdebug("trust", "considering partials");
            } else {
                /* We're all out of options, so we can't produce any more
                   candidates.  Let's calculate details and return the best
                   path we found. */
                builder->state = SecPathBuilderComputeDetails;
                return true;
            }
        }
        builder->partialIX = CFArrayGetCount(builder->partialPaths) - 1;
        secdebug("trust", "re-checking %d partials", builder->partialIX + 1);
        return true;
    }

    /* We know builder->partialIX >= 0 if we get here.  */
    SecCertificatePathRef partial = (SecCertificatePathRef)
        CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX);
    /* Don't try to extend partials anymore once we are in the considerPartials
       state, since at this point every partial has been extended with every
       possible parentSource already. */
    if (builder->considerPartials) {
        --builder->partialIX;
        SecPVCSetPath(&builder->path, partial, NULL);
        builder->state = SecPathBuilderValidatePath;
        return true;
    }

    /* Attempt to extend this partial path with another certificate. This
       should give us a list of potential parents to consider. */
    secdebug("trust", "looking for parents of partial %d/%d: %@",
        builder->partialIX + 1, CFArrayGetCount(builder->partialPaths),
        partial);

    /* Attempt to extend partial, leaving all possible extended versions
       of partial in builder->extendedPaths. */
	CFIndex sourceIX = SecCertificatePathGetNextSourceIndex(partial);
    CFIndex num_anchor_sources = CFArrayGetCount(builder->anchorSources);
    if (sourceIX < num_anchor_sources + builder->nextParentSource) {
        SecCertificateSourceRef source;
        if (sourceIX < num_anchor_sources) {
            source = (SecCertificateSourceRef)
                CFArrayGetValueAtIndex(builder->anchorSources, sourceIX);
            secdebug("trust", "searching anchor source %d/%d", sourceIX + 1,
                     num_anchor_sources);
        } else {
            CFIndex parentIX = sourceIX - num_anchor_sources;
            source = (SecCertificateSourceRef)
                CFArrayGetValueAtIndex(builder->parentSources, parentIX);
            secdebug("trust", "searching parent source %d/%d", parentIX + 1,
                     builder->nextParentSource);
        }
        SecCertificatePathSetNextSourceIndex(partial, sourceIX + 1);
        SecCertificateRef root = SecCertificatePathGetRoot(partial);
		return SecCertificateSourceCopyParents(source, root,
            builder, SecPathBuilderExtendPaths);
    } else {
        --builder->partialIX;
    }

    return true;
}
Beispiel #5
0
KeychainDbGlobal::~KeychainDbGlobal()
{
	secdebug("KCdb", "DbGlobal %p destroyed", this);
}
//
// Reset the connection.
// This discards all client state accumulated for the securityd link.
// Existing connections will go stale and fail; new connections will
// re-establish the link. This is an expert tool ONLY. If you don't know
// exactly how this gig is danced, you don't want to call this. Really.
//
void ClientSession::reset()
{
	secdebug("SSclnt", "resetting client state (OUCH)");
	mGlobal.reset();
}
Beispiel #7
0
//
// Contemplate the object-to-be-signed and set up the Signer state accordingly.
//
void SecCodeSigner::Signer::prepare(SecCSFlags flags)
{
	// get the Info.plist out of the rep for some creative defaulting
	CFRef<CFDictionaryRef> infoDict;
	if (CFRef<CFDataRef> infoData = rep->component(cdInfoSlot))
		infoDict.take(makeCFDictionaryFrom(infoData));

	// work out the canonical identifier
	identifier = state.mIdentifier;
	if (identifier.empty()) {
		identifier = rep->recommendedIdentifier(state);
		if (identifier.find('.') == string::npos)
			identifier = state.mIdentifierPrefix + identifier;
		if (identifier.find('.') == string::npos && state.isAdhoc())
			identifier = identifier + "-" + uniqueName();
		secdebug("signer", "using default identifier=%s", identifier.c_str());
	} else
		secdebug("signer", "using explicit identifier=%s", identifier.c_str());
	
	// work out the CodeDirectory flags word
	if (state.mCdFlagsGiven) {
		cdFlags = state.mCdFlags;
		secdebug("signer", "using explicit cdFlags=0x%x", cdFlags);
	} else {
		cdFlags = 0;
		if (infoDict)
			if (CFTypeRef csflags = CFDictionaryGetValue(infoDict, CFSTR("CSFlags"))) {
				if (CFGetTypeID(csflags) == CFNumberGetTypeID()) {
					cdFlags = cfNumber<uint32_t>(CFNumberRef(csflags));
					secdebug("signer", "using numeric cdFlags=0x%x from Info.plist", cdFlags);
				} else if (CFGetTypeID(csflags) == CFStringGetTypeID()) {
					cdFlags = cdTextFlags(cfString(CFStringRef(csflags)));
					secdebug("signer", "using text cdFlags=0x%x from Info.plist", cdFlags);
				} else
					MacOSError::throwMe(errSecCSBadDictionaryFormat);
			}
	}
	if (state.mSigner == SecIdentityRef(kCFNull))	// ad-hoc signing requested...
		cdFlags |= kSecCodeSignatureAdhoc;	// ... so note that
	
	// prepare the resource directory, if any
	string rpath = rep->resourcesRootPath();
	if (!rpath.empty()) {
		// explicitly given resource rules always win
		CFCopyRef<CFDictionaryRef> resourceRules = state.mResourceRules;
		
		// embedded resource rules come next
		if (!resourceRules && infoDict)
			if (CFTypeRef spec = CFDictionaryGetValue(infoDict, _kCFBundleResourceSpecificationKey)) {
				if (CFGetTypeID(spec) == CFStringGetTypeID())
					if (CFRef<CFDataRef> data = cfLoadFile(rpath + "/" + cfString(CFStringRef(spec))))
						if (CFDictionaryRef dict = makeCFDictionaryFrom(data))
							resourceRules.take(dict);
				if (!resourceRules)	// embedded rules present but unacceptable
					MacOSError::throwMe(errSecCSResourceRulesInvalid);
			}

		// finally, ask the DiskRep for its default
		if (!resourceRules)
			resourceRules.take(rep->defaultResourceRules(state));
		
		// build the resource directory
		ResourceBuilder resources(rpath, cfget<CFDictionaryRef>(resourceRules, "rules"), digestAlgorithm());
		rep->adjustResources(resources);	// DiskRep-specific adjustments
		CFRef<CFDictionaryRef> rdir = resources.build();
		resourceDirectory.take(CFPropertyListCreateXMLData(NULL, rdir));
	}
	
	// screen and set the signing time
	CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
	if (state.mSigningTime == CFDateRef(kCFNull)) {
		signingTime = 0;		// no time at all
	} else if (!state.mSigningTime) {
		signingTime = now;		// default
	} else {
		CFAbsoluteTime time = CFDateGetAbsoluteTime(state.mSigningTime);
		if (time > now)	// not allowed to post-date a signature
			MacOSError::throwMe(errSecCSBadDictionaryFormat);
		signingTime = time;
	}
	
	pagesize = state.mPageSize ? cfNumber<size_t>(state.mPageSize) : rep->pageSize(state);
    
    // Timestamping setup
    CFRef<SecIdentityRef> mTSAuth;	// identity for client-side authentication to the Timestamp server
}
void PIVKeyRecord::computeCrypt(PIVToken &pivToken, bool sign,	// MODIFY
	const AccessCredentials *cred,
	const byte_string &data, byte_string &output)
{
	if (data.size() != sizeInBits() / 8)
		CssmError::throwMe(CSSMERR_CSP_BLOCK_SIZE_MISMATCH);

	/* Allow all key usage, certificates determine validity */
	unsigned char algRef;
	switch (sizeInBits()) {
	case 1024:
		algRef = PIV_KEYALG_RSA_1024;
		break;
	case 2048:
		algRef = PIV_KEYALG_RSA_2048;
		break;
	default:
		/* Cannot use a key ~= 1024 or 2048 bits yet */
		CssmError::throwMe(CSSMERR_CSP_KEY_USAGE_INCORRECT);
		break;
	}

	/* Build the BER-Encoded message */
	/* Template: 0x7C L { 0x82 0x00, 0x81 L data } .. 2 tag+lengths + 1 tag-0 */
	TLVList commandList;
	commandList.push_back(TLV_ref(new TLV(0x81, data)));
	commandList.push_back(TLV_ref(new TLV(0x82)));
	TLV_ref command = TLV_ref(new TLV(0x7C, commandList));

	/* TODO: Evaluate result length handling */
	/* At least enough to contain BER-TLV */
	size_t resultLength = sizeInBits() / 8;
	resultLength += 1 + TLV::encodedLength(resultLength); // RESPONSE
	resultLength += 1 + 1; // Potential empty response-tlv
	resultLength += 1 + TLV::encodedLength(resultLength); // TLV containing response
	/* Round out resultLength to a multiple of 256 */
	resultLength = resultLength + resultLength % 256 + 256;
	// Ensure that there's enough space to prevent unnecessary resizing
	output.reserve(resultLength);

	PCSC::Transaction _(pivToken);
	pivToken.selectDefault();
	/* Support for the signing key w/ user-consent pin */
	if (cred)
	{
		uint32 size = cred->size();
		for (uint32 ix = 0; ix < size; ++ix)
		{
			const TypedList &sample = (*cred)[ix];
			if (sample.type() == CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD
				&& sample.length() == 2)
			{
				CssmData &pin = sample[1].data();
				if (pin.Length > 0)
				{
					pivToken.verifyPIN(1, pin.Data, pin.Length);
					break;
				}
				else if (pin.Length == 0)
				{
					// %%% <rdar://4334623>
					// PIN previously verified by securityd;
					// continue to look at remaining samples
				}
				else
				{
					CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
				}
			}
		}
	}

	byte_string commandString = command->encode();
	PIVError::check(pivToken.exchangeChainedAPDU(0x00, 0x87, algRef, keyRef, commandString, output));

	/* DECODE 0x7C */
	TLV_ref tlv;
	try {
		tlv = TLV::parse(output);
	} catch(...) {
		secure_zero(output);
		PIVError::throwMe(SCARD_RETURNED_DATA_CORRUPTED);
	}
	secure_zero(output);
	if(tlv->getTag() != (unsigned char*)"\x7C") {
		secdebug("piv", " %s: computeCrypt: missing response tag: 0x%.2X",
				 description(), 0x7C);
		PCSC::Error::throwMe(SCARD_E_PROTO_MISMATCH);
	}
	byte_string tagData;
	try {
		TLVList list = tlv->getInnerValues();
		TLVList::const_iterator iter = find_if(list.begin(), list.end(), TagPredicate(0x82));
		if(iter != list.end())
			tagData = (*iter)->getValue();
	} catch(...) {
	}
	if(tagData.size() == 0) {
		secdebug("piv", " %s: computeCrypt: missing response value tag: 0x%.2X",
				 description(), 0x82);
		PCSC::Error::throwMe(SCARD_E_PROTO_MISMATCH);
	}

	if(tagData.size() != sizeInBits() / 8) { // Not enough data at all..
		secure_zero(tagData);
		secdebug("piv", " %s: computeCrypt: expected contained response length: %ld, got: %ld",
				 description(), sizeInBits() / 8, tagData.size());
		PCSC::Error::throwMe(SCARD_E_PROTO_MISMATCH);
	}

	output.swap(tagData);
	/* zero-out tagData */
	secure_zero(tagData);
}
Beispiel #9
0
void BELPICKeyHandle::verifySignature(const Context &context,
	CSSM_ALGORITHMS signOnly, const CssmData &input, const CssmData &signature)
{
	secdebug("crypto", "verifySignature");
	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
void
AuthHostInstance::childAction()
{
	// switch to desired session
	CommonCriteria::AuditInfo &audit = this->session().auditInfo();
	audit.get(audit.sessionId());
	audit.set();
	//this->session().auditInfo().set();

	// Setup the environment for the SecurityAgent
	unsetenv("USER");
	unsetenv("LOGNAME");
	unsetenv("HOME");
				
	// close down any files that might have been open at this point
	int maxDescriptors = getdtablesize ();
	int i;
	
	int devnull = open(_PATH_DEVNULL, O_RDWR, 0);
	if (devnull >= 0) for (i = 0; i < 3; ++i)
	{
		dup2(devnull, i);
	}
	
	for (i = 3; i < maxDescriptors; ++i)
	{
		close (i);
	}
	
	// construct path to SecurityAgent
	char agentExecutable[PATH_MAX + 1];
	const char *path = getenv("SECURITYAGENT");
	if (!path)
		path = "/System/Library/CoreServices/SecurityAgent.app";
	secdebug("adhoc", "hostType = %d", mHostType);

	if ((mHostType == userAuthHost) || (mHostType == privilegedAuthHost))
	{
		snprintf(agentExecutable, sizeof(agentExecutable), "%s/Contents/Resources/authorizationhost", path);
		secdebug("AuthHostInstance", "execl(%s)", agentExecutable);
		execl(agentExecutable, agentExecutable, NULL);
	}
	else
	{
		snprintf(agentExecutable, sizeof(agentExecutable), "%s/Contents/MacOS/SecurityAgent", path);

		pid_t pid = getpid();
		if ((pid <= 0) ||
            sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &pid, sizeof(pid)))
				syslog(LOG_ERR, "Failed to set vfs.generic.noremotehang for pid(%d)", pid);

		setgroups(1, &agent_gid);
		setgid(agent_gid);
		setuid(agent_uid);

		secdebug("AuthHostInstance", "execl(%s) as user (%d,%d)", agentExecutable, agent_uid, agent_gid);
		execl(agentExecutable, agentExecutable, NULL);
	}

	secdebug("AuthHostInstance", "execl failed, errno=%d", errno);
	// Unconditional suicide follows.
	_exit(1);
}
void CountingMutex::finishEnter()
{
    mCount++;
    secdebug("cmutex", "%p finish up to %d", this, mCount);
    unlock();
}
AuthHostInstance::~AuthHostInstance()
{ 
	secdebug("authhost", "authhost died (%p)", this);
}
Beispiel #13
0
/* AUDIT[securityd](done):
   receiver (unused) is a mach_port owned by this process.
   reply (checked by mig) is a caller provided mach_port.
   auditToken (ok) is a kernel provided audit token.
   request_id (checked by mig) is caller provided value, that matches the
       mig entry for this function.
   msg_id (ok) is caller provided value.
   msg_data (ok) is a caller provided data of length:
   msg_length (ok).
 */
kern_return_t securityd_server_request(mach_port_t receiver, mach_port_t reply,
        audit_token_t auditToken,
        uint32_t request_id, uint32_t msg_id, uint8_t *msg_data,
        mach_msg_type_number_t msg_length)
{
    CFTypeRef args_in = NULL;
    CFTypeRef args_out = NULL;
    bool sendResponse = true;
    const char *op_name;

    request_begin();

    if (msg_length) {
        CFDataRef data_in = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
            msg_data, msg_length, kCFAllocatorNull);
        if (data_in) {
            args_in = CFPropertyListCreateFromXMLData(kCFAllocatorDefault,
                data_in, kCFPropertyListImmutable, NULL);
            CFRelease(data_in);
        }
    }

#if 0
    static int crash_counter = 0;
    if (crash_counter++) {
        secdebug("server", "crash test");
        exit(1);
    }
#endif

    SecTaskRef clientTask = 
#if CHECK_ENTITLEMENTS
    SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken);
#else 
    NULL;
#endif
    CFArrayRef groups = SecTaskCopyAccessGroups(clientTask);
    SecAccessGroupsSetCurrent(groups);
    OSStatus status = errSecParam;
    switch(msg_id) {
        case sec_item_add_id:
            op_name = "SecItemAdd";
            if (isDictionary(args_in))
                status = _SecItemAdd(args_in, &args_out, groups);
            break;
        case sec_item_copy_matching_id:
            op_name = "SecItemCopyMatching";
            if (isDictionary(args_in))
                status = _SecItemCopyMatching(args_in, &args_out, groups);
            break;
        case sec_item_delete_id:
            op_name = "SecItemDelete";
            if (isDictionary(args_in))
                status = _SecItemDelete(args_in, groups);
            break;
        case sec_item_update_id:
            op_name = "SecItemUpdate";
            if (isArrayOfLength(args_in, 2)) {
                CFDictionaryRef
                    in0 = (CFDictionaryRef)CFArrayGetValueAtIndex(args_in, 0),
                    in1 = (CFDictionaryRef)CFArrayGetValueAtIndex(args_in, 1);
                if (isDictionary(in0) && isDictionary(in1))
                    status = _SecItemUpdate(in0, in1, groups);
            }
            break;
        case sec_trust_store_contains_id:
        {
            op_name = "SecTrustStoreContains";
            if (!isArray(args_in))
                break;
            CFIndex argc_in = CFArrayGetCount(args_in);
            if (argc_in != 2)
                break;
            CFStringRef domainName = CFArrayGetValueAtIndex(args_in, 0);
            CFDataRef digest = CFArrayGetValueAtIndex(args_in, 1);
            if (!isString(domainName) || !isData(digest))
                break;

            SecTrustStoreRef ts = SecTrustStoreForDomainName(domainName);
            status = !SecTrustStoreContainsCertificateWithDigest(ts, digest);
            break;
        }
        case sec_trust_store_set_trust_settings_id:
        {
            op_name = "SecTrustStoreSetTrustSettings";
            /* Open the trust store unconditially so we can abuse this method
               even in clients that just want to read from the truststore,
               and this call will force it to be created. */
            SecTrustStoreRef ts = SecTrustStoreForDomain(kSecTrustStoreDomainUser);
            if (!isArray(args_in))
                break;
            CFIndex argc_in = CFArrayGetCount(args_in);
            if (argc_in != 1 && argc_in != 2)
                break;
            if (!SecTaskGetBooleanValueForEntitlement(clientTask,
                kSecEntitlementModifyAnchorCertificates)) {
                status = errSecMissingEntitlement;
                break;
            }
            CFDataRef certificateData = (CFDataRef)CFArrayGetValueAtIndex(args_in, 0);
            if (!isData(certificateData))
                break;
            SecCertificateRef certificate = SecCertificateCreateWithData(NULL, certificateData);
            if (certificate) {
                CFTypeRef trustSettingsDictOrArray;
                if (argc_in < 2) {
                    trustSettingsDictOrArray = NULL;
                } else {
                    trustSettingsDictOrArray = CFArrayGetValueAtIndex(args_in, 1);
                    if (trustSettingsDictOrArray) {
                        CFTypeID tst = CFGetTypeID(trustSettingsDictOrArray);
                        if (tst != CFArrayGetTypeID() && tst != CFDictionaryGetTypeID()) {
                            CFRelease(certificate);
                            break;
                        }
                    }
                }
                status = _SecTrustStoreSetTrustSettings(ts, certificate, trustSettingsDictOrArray);
                CFRelease(certificate);
            }
            break;
        }
        case sec_trust_store_remove_certificate_id:
            op_name = "SecTrustStoreRemoveCertificate";
            if (SecTaskGetBooleanValueForEntitlement(clientTask,
                    kSecEntitlementModifyAnchorCertificates)) {
                SecTrustStoreRef ts = SecTrustStoreForDomain(kSecTrustStoreDomainUser);
                if (isData(args_in)) {
                    status = SecTrustStoreRemoveCertificateWithDigest(ts, args_in);
                }
            } else {
                status = errSecMissingEntitlement;
            }
            break;
        case sec_delete_all_id:
            op_name = "SecDeleteAll";
            if (SecTaskGetBooleanValueForEntitlement(clientTask,
                kSecEntitlementWipeDevice)) {
                status = SecItemDeleteAll();
            } else {
                status = errSecMissingEntitlement;
            }
            break;
        case sec_trust_evaluate_id:
            op_name = "SecTrustEvaluate";
            if (isDictionary(args_in)) {
                struct securityd_server_trust_evaluation_context *tec = malloc(sizeof(*tec));
                tec->reply = reply;
                tec->request_id = request_id;
                status = SecTrustServerEvaluateAsync(args_in,
                    securityd_server_trust_evaluate_done, tec);
                if (status == noErr || status == errSecWaitForCallback) {
                    sendResponse = false;
                } else {
                    free(tec);
                }
            }
            break;
        case sec_restore_keychain_id:
            op_name = "SecRestoreKeychain";
            if (SecTaskGetBooleanValueForEntitlement(clientTask,
                kSecEntitlementRestoreKeychain)) {
                status = _SecServerRestoreKeychain();
            } else {
                status = errSecMissingEntitlement;
            }
            break;
        case sec_migrate_keychain_id:
            op_name = "SecMigrateKeychain";
            if (isArray(args_in)) {
                if (SecTaskGetBooleanValueForEntitlement(clientTask,
                    kSecEntitlementMigrateKeychain)) {
                    status = _SecServerMigrateKeychain(args_in, &args_out);
                } else {
                    status = errSecMissingEntitlement;
                }
            }
            break;
        case sec_keychain_backup_id:
            op_name = "SecKeychainBackup";
            if (!args_in || isArray(args_in)) {
                if (SecTaskGetBooleanValueForEntitlement(clientTask,
                    kSecEntitlementRestoreKeychain)) {
                    status = _SecServerKeychainBackup(args_in, &args_out);
                } else {
                    status = errSecMissingEntitlement;
                }
            }
            break;
        case sec_keychain_restore_id:
            op_name = "SecKeychainRestore";
            if (isArray(args_in)) {
                if (SecTaskGetBooleanValueForEntitlement(clientTask,
                    kSecEntitlementRestoreKeychain)) {
                    status = _SecServerKeychainRestore(args_in, &args_out);
                } else {
                    status = errSecMissingEntitlement;
                }
            }
            break;
        default:
            op_name = "invalid_operation";
            status = errSecParam;
            break;
    }

    const char *proc_name;
#ifdef NDEBUG
    if (status == errSecMissingEntitlement) {
#endif
        pid_t pid;
        audit_token_to_au32(auditToken, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
        int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
        struct kinfo_proc kp;
        size_t len = sizeof(kp);
        if (sysctl(mib, 4, &kp, &len, NULL, 0) == -1 || len == 0)
            proc_name = strerror(errno);
        else
            proc_name = kp.kp_proc.p_comm;

#ifndef NDEBUG
    if (status == errSecMissingEntitlement) {
#endif
        asl_log(NULL, NULL, ASL_LEVEL_ERR,
            "%s[%u] %s: missing entitlement", proc_name, pid, op_name);
        /* Remap errSecMissingEntitlement -> errSecInteractionNotAllowed. */
        status = errSecInteractionNotAllowed;
    }

    secdebug("ipc", "%s[%u] %s: returning: %d", proc_name, pid, op_name,
        status);

    CFReleaseSafe(groups);
    CFReleaseSafe(clientTask);
    SecAccessGroupsSetCurrent(NULL);

    kern_return_t err = 0;
    if (sendResponse)
        err = securityd_server_send_reply(reply, request_id, status, args_out);

    CFReleaseSafe(args_in);

    return err;
}

extern boolean_t securityd_request_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);

union max_msg_size_union {
    union __RequestUnion__securityd_client_securityd_reply_subsystem reply;
};

static uint8_t reply_buffer[sizeof(union max_msg_size_union) + MAX_TRAILER_SIZE];

static void *handle_message(void *msg, CFIndex size,
        CFAllocatorRef allocator, void *info)
{
    mach_msg_header_t *message = (mach_msg_header_t *)msg;
    mach_msg_header_t *reply = (mach_msg_header_t *)reply_buffer;

    securityd_request_server(message, reply);

    return NULL;
}
//
// Destroy it
//
UnlockReferralItem::~UnlockReferralItem() 
{
	secdebug("referral", "destroy %p", this);
}
//
// Construct a TokenDbCommon
//
TokenDbCommon::TokenDbCommon(Session &ssn, Token &tk, const char *name)
	: DbCommon(ssn), mDbName(name ? name : ""), mHasAclState(false), mResetLevel(0)
{
	secdebug("tokendb", "creating tokendbcommon %p: with token %p", this, &tk);
	parent(tk);
}
Beispiel #16
0
void BELPICKeyHandle::generateMac(const Context &context,
	const CssmData &input, CssmData &output)
{
	secdebug("crypto", "generateMac");
	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
TokenDbCommon::~TokenDbCommon()
{
	secdebug("tokendb", "destroying tokendbcommon %p", this);
	token().removeCommon(*this);		// unregister from Token
}
Beispiel #18
0
void BELPICKeyHandle::verifyMac(const Context &context,
	const CssmData &input, const CssmData &compare)
{
	secdebug("crypto", "verifyMac");
	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
Reader::~Reader()
{
	secdebug("reader", "%p (%s) destroyed", this, name().c_str());
}
Beispiel #20
0
void BELPICKeyHandle::encrypt(const Context &context,
	const CssmData &clear, CssmData &cipher)
{
	secdebug("crypto", "encrypt");
	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
static void SecPathBuilderInit(SecPathBuilderRef builder,
	CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly,
    CFArrayRef policies, CFAbsoluteTime verifyTime,
    SecPathBuilderCompleted completed, const void *context) {
    secdebug("alloc", "%p", builder);
	CFAllocatorRef allocator = kCFAllocatorDefault;

	builder->nextParentSource = 1;
	builder->considerPartials = false;
    builder->canAccessNetwork = true;

    builder->anchorSources = CFArrayCreateMutable(allocator, 0, NULL);
    builder->parentSources = CFArrayCreateMutable(allocator, 0, NULL);
    builder->allPaths = CFSetCreateMutable(allocator, 0,
		&kCFTypeSetCallBacks);

    builder->partialPaths = CFArrayCreateMutable(allocator, 0, NULL);
    builder->rejectedPaths = CFArrayCreateMutable(allocator, 0, NULL);
    builder->candidatePaths = CFArrayCreateMutable(allocator, 0, NULL);
    builder->partialIX = 0;

    /* Init the policy verification context. */
    SecPVCInit(&builder->path, builder, policies, verifyTime);
	builder->bestPath = NULL;
	builder->bestPathIsEV = false;
	builder->rejectScore = 0;

	/* Let's create all the certificate sources we might want to use. */
	builder->certificateSource =
		SecMemoryCertificateSourceCreate(certificates);
	if (anchors)
		builder->anchorSource = SecMemoryCertificateSourceCreate(anchors);
	else
		builder->anchorSource = NULL;

	/* We always search certificateSource for parents since it includes the
	   leaf itself and it might be self signed. */
	CFArrayAppendValue(builder->parentSources, builder->certificateSource);
	if (builder->anchorSource) {
		CFArrayAppendValue(builder->anchorSources, builder->anchorSource);
	}
	CFArrayAppendValue(builder->parentSources, &kSecItemCertificateSource);
    if (anchorsOnly) {
        /* Add the system and user anchor certificate db to the search list
           if we don't explicitly trust them. */
        CFArrayAppendValue(builder->parentSources, &kSecSystemAnchorSource);
        CFArrayAppendValue(builder->parentSources, &kSecUserAnchorSource);
    } else {
        /* Only add the system and user anchor certificate db to the
           anchorSources if we are supposed to trust them. */
        CFArrayAppendValue(builder->anchorSources, &kSecSystemAnchorSource);
        CFArrayAppendValue(builder->anchorSources, &kSecUserAnchorSource);
    }
    CFArrayAppendValue(builder->parentSources, &kSecCAIssuerSource);

	/* Now let's get the leaf cert and turn it into a path. */
	SecCertificateRef leaf =
		(SecCertificateRef)CFArrayGetValueAtIndex(certificates, 0);
	SecCertificatePathRef path = SecCertificatePathCreate(NULL, leaf);
	CFSetAddValue(builder->allPaths, path);
	CFArrayAppendValue(builder->partialPaths, path);
    if (SecPathBuilderIsAnchor(builder, leaf)) {
        SecCertificatePathSetIsAnchored(path);
        CFArrayAppendValue(builder->candidatePaths, path);
    }
    SecPathBuilderLeafCertificateChecks(builder, path);
	CFRelease(path);

    builder->activations = 0;
    builder->state = SecPathBuilderGetNext;
    builder->completed = completed;
    builder->context = context;
}
Beispiel #22
0
void BELPICKeyHandle::decrypt(const Context &context,
	const CssmData &cipher, CssmData &clear)
{
	secdebug("crypto", "decrypt alg: %u", context.algorithm());
	CssmError::throwMe(CSSMERR_CSP_KEY_USAGE_INCORRECT);
}
Beispiel #23
0
//
// Perform deferred lock processing for a database.
//
void KeychainDbCommon::action()
{
	secdebug("KCdb", "common %s(%p) locked by timer", dbName(), this);
	lockDb();
}
Beispiel #24
0
void BELPICKeyHandle::exportKey(const Context &context,
	const AccessCredentials *cred, CssmKey &wrappedKey)
{
	secdebug("crypto", "exportKey");
	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
Beispiel #25
0
//
// Given an AccessCredentials for this database, wring out the existing primary
// database secret by whatever means necessary.
// On entry, caller must hold the database common lock. It will be held
// throughout except when user interaction is required. User interaction 
// requires relinquishing the database common lock and taking the UI lock. On
// return from user interaction, the UI lock is relinquished and the database
// common lock must be reacquired. At no time may the caller hold both locks.
// On exit, the crypto core has its master secret. If things go wrong,
// we will throw a suitable exception. Note that encountering any malformed
// credential sample will throw, but this is not guaranteed -- don't assume
// that NOT throwing means creds is entirely well-formed (it may just be good
// enough to work THIS time).
//
// How this works:
// Walk through the creds. Fish out those credentials (in order) that
// are for unlock processing (they have no ACL subject correspondents),
// and (try to) obey each in turn, until one produces a valid secret
// or you run out. If no special samples are found at all, interpret that as
// "use the system global default," which happens to be hard-coded right here.
//
void KeychainDatabase::establishOldSecrets(const AccessCredentials *creds)
{
	bool forSystem = this->belongsToSystem();	// this keychain belongs to the system security domain

	// attempt system-keychain unlock
	if (forSystem) {
		SystemKeychainKey systemKeychain(kSystemUnlockFile);
		if (systemKeychain.matches(mBlob->randomSignature)) {
			secdebug("KCdb", "%p attempting system unlock", this);
			common().setup(mBlob, CssmClient::Key(Server::csp(), systemKeychain.key(), true));
			if (decode())
				return;
		}
	}
    
	list<CssmSample> samples;
	if (creds && creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, samples)) {
		for (list<CssmSample>::iterator it = samples.begin(); it != samples.end(); it++) {
			TypedList &sample = *it;
			sample.checkProper();
			switch (sample.type()) {
			// interactively prompt the user - no additional data
			case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT:
				if (!forSystem) {
					if (interactiveUnlock())
						return;
				}
                break;
			// try to use an explicitly given passphrase - Data:passphrase
			case CSSM_SAMPLE_TYPE_PASSWORD:
				if (sample.length() != 2)
					CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
				secdebug("KCdb", "%p attempting passphrase unlock", this);
				if (decode(sample[1]))
					return;
				break;
			// try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey
			case CSSM_SAMPLE_TYPE_SYMMETRIC_KEY:
			case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY:
				assert(mBlob);
				secdebug("KCdb", "%p attempting explicit key unlock", this);
				common().setup(mBlob, keyFromCreds(sample, 4));
				if (decode())
					return;
				break;
			// explicitly defeat the default action but don't try anything in particular
			case CSSM_WORDID_CANCELED:
				secdebug("KCdb", "%p defeat default action", this);
				break;
			default:
				// Unknown sub-sample for unlocking.
				// If we wanted to be fascist, we could now do
				//  CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
				// But instead we try to be tolerant and continue on.
				// This DOES however count as an explicit attempt at specifying unlock,
				// so we will no longer try the default case below...
				secdebug("KCdb", "%p unknown sub-sample unlock (%d) ignored", this, sample.type());
				break;
			}
		}
	} else {
		// default action
		assert(mBlob);

		if (!forSystem) {
			if (interactiveUnlock())
				return;
		}
	}
	
	// out of options - no secret obtained
	CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
}
Beispiel #26
0
uint32 BELPICKeyHandle::getOutputSize(const Context &context,
	uint32 inputSize, bool encrypting)
{
	secdebug("crypto", "getOutputSize");
	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
//
// Destroy it
//
UserTrustItem::~UserTrustItem() 
{
	secdebug("usertrust", "%p destroyed", this);
}
Beispiel #28
0
void BELPICKeyHandle::generateSignature(const Context &context,
	CSSM_ALGORITHMS signOnly, const CssmData &input, CssmData &signature)
{
	secdebug("crypto", "generateSignature alg: %u signOnly: %u",
		context.algorithm(), signOnly);
	IFDUMPING("crypto", context.dump("signature context"));

	if (context.type() != CSSM_ALGCLASS_SIGNATURE)
		CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);

	if (context.algorithm() != CSSM_ALGID_RSA)
		CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);

	// Find out if we are doing a SHA1 or MD5 signature and setup header to
	// point to the right asn1 blob.
	const unsigned char *header;
	size_t headerLength;
	if (signOnly == CSSM_ALGID_SHA1)
	{
		if (input.Length != 20)
			CssmError::throwMe(CSSMERR_CSP_BLOCK_SIZE_MISMATCH);

		header = sha1sigheader;
		headerLength = sizeof(sha1sigheader);
	}
	else if (signOnly == CSSM_ALGID_MD5)
	{
		if (input.Length != 16)
			CssmError::throwMe(CSSMERR_CSP_BLOCK_SIZE_MISMATCH);

		header = md5sigheader;
		headerLength = sizeof(md5sigheader);
	}
	else if (signOnly == CSSM_ALGID_NONE)
	{
		// Special case used by SSL it's an RSA signature, without the ASN1
		// stuff
		header = NULL;
		headerLength = 0;

		// @@@ Fix me
		//CssmError::throwMe(CSSMERR_CSP_BLOCK_SIZE_MISMATCH);
	}
	else
		CssmError::throwMe(CSSMERR_CSP_INVALID_DIGEST_ALGORITHM);

#if 0
	// @@@ Hack for BELPIC card!
	header = NULL;
	headerLength = 0;
#endif

	// Create an input buffer in which we construct the data we will send to
	// the token.
	size_t inputDataSize = headerLength + input.Length;
	size_t keyLength = mKey.sizeInBits() / 8;
	auto_array<unsigned char> inputData(keyLength);
	unsigned char *to = inputData.get();

	// Get padding, but default to pkcs1 style padding
	uint32 padding = CSSM_PADDING_PKCS1;
	context.getInt(CSSM_ATTRIBUTE_PADDING, padding);

#if 1
	if (padding != CSSM_PADDING_PKCS1)
		CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING);
#else
	if (padding == CSSM_PADDING_PKCS1)
	{
		// Add PKCS1 style padding
		*(to++) = 0;
		*(to++) = 1; /* Private Key Block Type. */
		size_t padLength = keyLength - 3 - inputDataSize;
		memset(to, 0xff, padLength);
		to += padLength;
		*(to++) = 0;
		inputDataSize = keyLength;
	}
	else if (padding == CSSM_PADDING_NONE)
	{
		// Token will fail if the input data isn't exactly keysize / 8 octects
		// long
	}
	else
		CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING);
#endif

	// Now copy the ASN1 header into the input buffer.
	// This header is the DER encoding of
	// DigestInfo ::= SEQUENCE { digestAlgorithm AlgorithmIdentifier,
	// digest OCTET STRING }
	// Where AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER,
	// parameters OPTIONAL ANY }
	if (headerLength)
	{
		memcpy(to, header, headerLength);
		to += headerLength;
	}

	// Finally copy the passed in data to the input buffer.
	memcpy(to, input.Data, input.Length);

	// @@@ Switch to using tokend allocators
	unsigned char *outputData =
		reinterpret_cast<unsigned char *>(malloc(keyLength));
	size_t outputLength = keyLength;
	try
	{
		const AccessCredentials *cred = context.get<const AccessCredentials>(
			CSSM_ATTRIBUTE_ACCESS_CREDENTIALS);
		// Sign the inputData using the token
		mKey.computeCrypt(mToken, true, cred, inputData.get(), inputDataSize,
			outputData, outputLength);
	}
	catch (...)
	{
		// @@@ Switch to using tokend allocators
		free(outputData);
		throw;
	}

	signature.Data = outputData;
	signature.Length = outputLength;
}
bool asyncHttpPost(CFURLRef responder, CFDataRef requestData /* , bool force_nocache */ ,
    asynchttp_t *http) {
    bool result = true; /* True, we didn't schedule any work. */
	/* resources to release on exit */
    CFURLRef getURL = NULL;

/* Interesting tidbit from rfc5019
   When sending requests that are less than or equal to 255 bytes in
   total (after encoding) including the scheme and delimiters (http://),
   server name and base64-encoded OCSPRequest structure, clients MUST
   use the GET method (to enable OCSP response caching).  OCSP requests
   larger than 255 bytes SHOULD be submitted using the POST method.

   Interesting tidbit from rfc2616:
   Note: Servers ought to be cautious about depending on URI lengths
   above 255 bytes, because some older client or proxy
   implementations might not properly support these lengths.

   Given the second note I'm assuming that the note in rfc5019 is about the
   length of the URI, not the length of the entire HTTP request.

   If we need to consider the entire request we need to have 17 bytes less, or
   17 + 25 = 42 if we are appending a "Cache-Control: no-cache CRLF" header
   field.

   The 17 and 42 above are based on the request encoding from rfc2616
   Method SP Request-URI SP HTTP-Version CRLF (header CRLF)* CRLF
   so in our case it's:
   GET SP URI SP HTTP/1.1 CRLF CRLF
   17 + len(URI) bytes
   or
   GET SP URI SP HTTP/1.1 CRLF Cache-Control: SP no-cache CRLF CRLF
   42 + len(URI) bytes
 */

    /* First let's try creating a GET request. */
    getURL = createGetURL(responder, requestData);
    if (getURL && CFURLGetBytes(getURL, NULL, 0) < 256) {
        /* Get URI is less than 256 bytes encoded, making it safe even for
           older proxy or caching servers, so let's use HTTP GET. */
        secdebug("http", "GET[%ld] %@", CFURLGetBytes(getURL, NULL, 0), getURL);
        require_quiet(http->request = CFHTTPMessageCreateRequest(kCFAllocatorDefault,
            CFSTR("GET"), getURL, kCFHTTPVersion1_1), errOut);
    } else {
        /* GET Request too big to ensure error free transmission, let's
           create a HTTP POST http->request instead. */
        secdebug("http", "POST %@ CRLF body", responder);
        require_quiet(http->request = CFHTTPMessageCreateRequest(kCFAllocatorDefault,
            CFSTR("POST"), responder, kCFHTTPVersion1_1), errOut);
        /* Set the body and required header fields. */
        CFHTTPMessageSetBody(http->request, requestData);
        CFHTTPMessageSetHeaderFieldValue(http->request, kContentType,
            kAppOcspRequest);
    }

#if 0
    if (force_nocache) {
        CFHTTPMessageSetHeaderFieldValue(http->request, CFSTR("Cache-Control"),
            CFSTR("no-cache"));
    }
#endif

    result = asynchttp_request(NULL, http);

errOut:
    CFReleaseSafe(getURL);

    return result;
}
void LoadablePlugin::unload()
{
	secdebug("cssm", "LoadablePlugin::unload() path %s", path().c_str());
	/* skipping for workaround for radar 3774226 
    LoadableBundle::unload(); */ 
}