Example #1
0
bool encryptionEnabled(SecKeyRef privateKeyRef)
{
	/*
		Since CSSM searching for attributes is an AND, not an OR, we need to get all
		identities then check each one for a good key usage. Note that for the CAC
		card, the "Email Encryption Private Key" only has the unwrap bit set (0x1A).
		Return true if this identity supports appropriate encryption.
	*/

	UInt32 tag[] = { kSecKeyEncrypt, kSecKeyDecrypt, kSecKeyDerive, kSecKeyWrap, kSecKeyUnwrap };
	UInt32 format[] = { CSSM_DB_ATTRIBUTE_FORMAT_UINT32, CSSM_DB_ATTRIBUTE_FORMAT_UINT32, 
		CSSM_DB_ATTRIBUTE_FORMAT_UINT32, CSSM_DB_ATTRIBUTE_FORMAT_UINT32, CSSM_DB_ATTRIBUTE_FORMAT_UINT32};
	SecKeychainAttributeInfo info = { 5, tag, format }; // attrs to retrieve

	SecKeychainAttributeList *attrList = NULL;
	OSStatus status = SecKeychainItemCopyAttributesAndData((SecKeychainItemRef)privateKeyRef, &info, NULL, &attrList, 0, NULL);
	if (status || !attrList)
		return false;

	bool canEncrypt = false;
	for (uint32_t index = 0; index < attrList->count; ++index)
	{
		if (attrList->attr[index].length != sizeof(uint32_t) || !attrList->attr[index].data ||
			0 == *(uint32_t*)attrList->attr[index].data)
			continue;
		canEncrypt = true;
		break;
	}

	status = SecKeychainItemFreeAttributesAndData(attrList, NULL);
	return canEncrypt;
}
/*
 * Determine if specified SecCertificateRef is a self-signed cert.
 * We do this by comparing the subject and issuerr names; no cryptographic
 * verification is performed.
 *
 * Returns true if the cert appears to be a root. 
 */
static bool isCertRefRoot(
	SecCertificateRef certRef)
{
	bool brtn = false;
#if 0
	/* just search for the two attrs we want */
	UInt32 tags[2] = {kSecSubjectItemAttr, kSecIssuerItemAttr};
	SecKeychainAttributeInfo attrInfo;
	attrInfo.count = 2;
	attrInfo.tag = tags;
	attrInfo.format = NULL;
	SecKeychainAttributeList *attrList = NULL;
	SecKeychainAttribute *attr1 = NULL;
	SecKeychainAttribute *attr2 = NULL;
	
	OSStatus ortn = SecKeychainItemCopyAttributesAndData(
		(SecKeychainItemRef)certRef, 
		&attrInfo,
		NULL,			// itemClass
		&attrList, 
		NULL,			// length - don't need the data
		NULL);			// outData
	if(ortn) {
		cssmPerror("SecKeychainItemCopyAttributesAndData", ortn);
		/* may want to be a bit more robust here, but this should
		 * never happen */
		return false;
	}
	/* subsequent errors to errOut: */
	
	if((attrList == NULL) || (attrList->count != 2)) {
		printf("***Unexpected result fetching label attr\n");
		goto errOut;
	}
	
	/* rootness is just byte-for-byte compare of the two names */ 
	attr1 = &attrList->attr[0];
	attr2 = &attrList->attr[1];
	if(attr1->length == attr2->length) {
		if(memcmp(attr1->data, attr2->data, attr1->length) == 0) {
			brtn = true;
		}
	}
errOut:
	SecKeychainItemFreeAttributesAndData(attrList, NULL);
#endif
	return brtn;
}
Example #3
0
OSStatus findCertificatePublicKeyHash(SecCertificateRef certificate, CFDataRef *label)
{
	UInt32 tag[1] = { kSecPublicKeyHashItemAttr };	// kSecKeyLabel == hash public key	[kSecPublicKeyHashItemAttr ??kSecKeyLabel]
	UInt32 format[1] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB };
	SecKeychainAttributeInfo info = { 1, tag, format }; // attrs to retrieve

	SecKeychainAttributeList *attrList = NULL;
		
	OSStatus status = SecKeychainItemCopyAttributesAndData(SecKeychainItemRef(certificate), &info, NULL, &attrList, 0, NULL);
	if (status || !attrList || !attrList->count)
		return status;

	const uint32_t index = 0;
	if (attrList->attr[index].tag == kSecPublicKeyHashItemAttr)
		*label = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)attrList->attr[index].data, attrList->attr[index].length);

	SecKeychainItemFreeAttributesAndData(attrList, NULL);
	return noErr;
}
Example #4
0
static int
getAttribute(SecKeychainItemRef itemRef, SecItemAttr item,
	     SecKeychainAttributeList **attrs)
{	     
    SecKeychainAttributeInfo attrInfo;
    uint32 attrFormat = 0;
    OSStatus ret;

    *attrs = NULL;

    attrInfo.count = 1;
    attrInfo.tag = &item;
    attrInfo.format = &attrFormat;
  
    ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
					       attrs, NULL, NULL);
    if (ret)
	return EINVAL;
    return 0;
}
Example #5
0
void genKeychainItem(const SecKeychainItemRef& item, QueryData& results) {
  Row r;

  // Create an info structure with 1 tag, then iterate over setting the tag
  // type to assure maximum compatibility with the various Keychain items.
  SecKeychainAttributeInfo info;
  UInt32 tags[1];
  info.count = sizeof(tags) / sizeof(UInt32);
  info.tag = tags;
  info.format = nullptr;

  SecItemClass item_class = 0;
  SecKeychainAttributeList* attr_list = nullptr;

  // Any tag that does not exist for the item will prevent the entire result.
  for (const auto& attr_tag : kKeychainItemAttrs) {
    tags[0] = attr_tag.first;
    SecKeychainItemCopyAttributesAndData(
        item, &info, &item_class, &attr_list, 0, nullptr);

    if (attr_list != nullptr) {
      // Expect each specific tag to return string data.
      for (int i = 0; i < attr_list->count; ++i) {
        SecKeychainAttribute* attr = &attr_list->attr[i];
        if (attr->length > 0) {
          r[attr_tag.second] = std::string((char*)attr->data, attr->length);
        }
      }
      SecKeychainItemFreeAttributesAndData(attr_list, nullptr);
      attr_list = nullptr;
    }
  }

  // The keychain item class is obtained each time and will be consistent.
  if (kKeychainItemClasses.count(item_class) > 0) {
    r["type"] = kKeychainItemClasses.at(item_class);
  }

  r["path"] = getKeychainPath(item);
  results.push_back(r);
}
Example #6
0
static VALUE rb_keychain_item_copy_password(VALUE self){
  void *data;
  SecKeychainItemRef keychainItem=NULL;
  UInt32 dataLength;
  Data_Get_Struct(self, struct OpaqueSecKeychainItemRef, keychainItem);

  VALUE unsaved = rb_ivar_get(self, rb_intern("unsaved_password"));


  if(!NIL_P(unsaved)){
    return unsaved;
  }
  else{
    OSStatus result = SecKeychainItemCopyAttributesAndData(keychainItem, NULL , NULL, NULL, &dataLength, &data);

    CheckOSStatusOrRaise(result);

    VALUE rb_data = rb_enc_str_new(data, dataLength, rb_ascii8bit_encoding());
    SecKeychainItemFreeAttributesAndData(NULL,data);
    return rb_data;
  }
}
Example #7
0
static int
keychain_iter(hx509_context context,
	      hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
{
    SecKeychainAttributeList *attrs = NULL;
    SecKeychainAttributeInfo attrInfo;
    uint32 attrFormat[1] = { 0 };
    SecKeychainItemRef itemRef;
    SecItemAttr item[1];
    struct iter *iter = cursor;
    OSStatus ret;
    UInt32 len;
    void *ptr = NULL;

    if (iter->certs)
	return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert);

    *cert = NULL;

    ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef);
    if (ret == errSecItemNotFound)
	return 0;
    else if (ret != 0)
	return EINVAL;
	
    /*
     * Pick out certificate and matching "keyid"
     */

    item[0] = kSecPublicKeyHashItemAttr;

    attrInfo.count = 1;
    attrInfo.tag = item;
    attrInfo.format = attrFormat;
  
    ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
					       &attrs, &len, &ptr);
    if (ret)
	return EINVAL;

    ret = hx509_cert_init_data(context, ptr, len, cert);
    if (ret)
	goto out;

    /* 
     * Find related private key if there is one by looking at
     * kSecPublicKeyHashItemAttr == kSecKeyLabel
     */
    {
	SecKeychainSearchRef search;
	SecKeychainAttribute attrKeyid;
	SecKeychainAttributeList attrList;

	attrKeyid.tag = kSecKeyLabel;
	attrKeyid.length = attrs->attr[0].length;
	attrKeyid.data = attrs->attr[0].data;
	
	attrList.count = 1;
	attrList.attr = &attrKeyid;

	ret = SecKeychainSearchCreateFromAttributes(NULL,
						    CSSM_DL_DB_RECORD_PRIVATE_KEY,
						    &attrList,
						    &search);
	if (ret) {
	    ret = 0;
	    goto out;
	}

	ret = SecKeychainSearchCopyNext(search, &itemRef);
	CFRelease(search);
	if (ret == errSecItemNotFound) {
	    ret = 0;
	    goto out;
	} else if (ret) {
	    ret = EINVAL;
	    goto out;
	}
	set_private_key(context, itemRef, *cert);
    }

out:
    SecKeychainItemFreeAttributesAndData(attrs, ptr);

    return ret;
}
Example #8
0
bool getCredentialsFromKeychain(const URI &uri, ClientRequest::ptr priorRequest,
    std::string &scheme, std::string &realm, std::string &username,
    std::string &password, size_t attempts)
{
    if (attempts != 1)
        return false;
    bool proxy =
       priorRequest->response().status.status == PROXY_AUTHENTICATION_REQUIRED;
    const ChallengeList &challengeList = proxy ?
        priorRequest->response().response.proxyAuthenticate :
        priorRequest->response().response.wwwAuthenticate;
    if (isAcceptable(challengeList, "Basic"))
        scheme = "Basic";
    else if (isAcceptable(challengeList, "Digest"))
        scheme = "Digest";
    else
        return false;

    std::vector<SecKeychainAttribute> attrVector;
    std::string host = uri.authority.host();
    attrVector.push_back((SecKeychainAttribute){kSecServerItemAttr, host.size(),
       (void *)host.c_str()});

    UInt32 port = 0;
    if (uri.authority.portDefined()) {
        port = uri.authority.port();
        attrVector.push_back((SecKeychainAttribute){kSecPortItemAttr,
           sizeof(UInt32), &port});
    }
    SecProtocolType protocol;
    if (proxy && priorRequest->request().requestLine.method == CONNECT)
        protocol = kSecProtocolTypeHTTPSProxy;
    else if (proxy)
        protocol = kSecProtocolTypeHTTPProxy;
    else if (uri.scheme() == "https")
        protocol = kSecProtocolTypeHTTPS;
    else if (uri.scheme() == "http")
        protocol = kSecProtocolTypeHTTP;
    else
        MORDOR_NOTREACHED();
    attrVector.push_back((SecKeychainAttribute){kSecProtocolItemAttr,
        sizeof(SecProtocolType), &protocol});

    ScopedCFRef<SecKeychainSearchRef> search;
    SecKeychainAttributeList attrList;
    attrList.count = (UInt32)attrVector.size();
    attrList.attr = &attrVector[0];

    OSStatus status = SecKeychainSearchCreateFromAttributes(NULL,
        kSecInternetPasswordItemClass, &attrList, &search);
    if (status != 0)
        return false;
    ScopedCFRef<SecKeychainItemRef> item;
    status = SecKeychainSearchCopyNext(search, &item);
    if (status != 0)
        return false;
    SecKeychainAttributeInfo info;
    SecKeychainAttrType tag = kSecAccountItemAttr;
    CSSM_DB_ATTRIBUTE_FORMAT format = CSSM_DB_ATTRIBUTE_FORMAT_STRING;
    info.count = 1;
    info.tag = (UInt32 *)&tag;
    info.format = (UInt32 *)&format;
    
    SecKeychainAttributeList *attrs;
    UInt32 passwordLength = 0;
    void *passwordBytes = NULL;

    status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attrs,
        &passwordLength, &passwordBytes);
    if (status != 0)
        return false;

    try {
        username.assign((const char *)attrs->attr[0].data, attrs->attr[0].length);
        password.assign((const char *)passwordBytes, passwordLength);
    } catch (...) {
        SecKeychainItemFreeContent(attrs, passwordBytes);
        throw;
    }
    SecKeychainItemFreeContent(attrs, passwordBytes);
    return true;
}
void P12Coder::addSecCert(
	SecCertificateRef	certRef)
{
	/* get the cert's attrs and data */
	/* I don't know what the format field is for */
	SecKeychainAttributeInfo attrInfo;
	attrInfo.count = 2;
	UInt32 tags[2] = {kSecLabelItemAttr, kSecPublicKeyHashItemAttr};
	attrInfo.tag = tags;
	attrInfo.format = NULL;	// ???
	
	/* FIXME header says this is an IN/OUT param, but it's not */
	SecKeychainAttributeList *attrList = NULL;
	UInt32 certLen;
	void *certData;
	
	OSStatus ortn = SecKeychainItemCopyAttributesAndData(
		(SecKeychainItemRef)certRef, 
		&attrInfo,
		NULL,			// itemClass
		&attrList, 
		&certLen,	
		&certData);
	if(ortn) {
		p12ErrorLog("addSecCert: SecKeychainItemCopyAttributesAndData "
			"error\n");
		MacOSError::throwMe(ortn);		
	}
	
	/* Snag the attrs, convert to something useful */
	CFStringRef friendName = NULL;
	CFDataRef localKeyId = NULL;
	for(unsigned i=0; i<attrList->count; i++) {
		SecKeychainAttribute *attr = &attrList->attr[i];
		switch(attr->tag) {
			case kSecPublicKeyHashItemAttr:
				localKeyId = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length);
				break;
			case kSecLabelItemAttr:
				/* FIXME: always in UTF8? */
				friendName = CFStringCreateWithBytes(NULL, 
					(UInt8 *)attr->data, attr->length, kCFStringEncodingUTF8,
					false);
				break;
			default:
				p12ErrorLog("addSecCert: unexpected attr tag\n");
				MacOSError::throwMe(errSecParam);		
			
		}
	}
	
	/* Cook up a cert bag and save it */
	CSSM_DATA cData = {certLen, (uint8 *)certData};
	P12CertBag *certBag = new P12CertBag(CT_X509, cData, friendName,
		localKeyId, NULL, mCoder);
	addCert(certBag);
	SecKeychainItemFreeAttributesAndData(attrList, certData);
	if(friendName) {
		CFRelease(friendName);
	}
	if(localKeyId) {
		CFRelease(localKeyId);
	}
}
void P12Coder::addSecKey(
	SecKeyRef	keyRef)
{
	/* get the cert's attrs (not data) */
	
	/* 
	 * Convert the attr name strings we happen to know about to 
	 * unknowable name-as-int values.
	 */
	UInt32 printNameTag;
	OSStatus ortn = attrNameToInt(P12_KEY_ATTR_PRINT_NAME, &printNameTag);
	if(ortn) {
		p12ErrorLog("addSecKey: problem looking up key attr name\n");
		MacOSError::throwMe(ortn);
	}
	UInt32 labelHashTag;
	ortn = attrNameToInt(P12_KEY_ATTR_LABEL_AND_HASH, &labelHashTag);
	if(ortn) {
		p12ErrorLog("addSecKey: problem looking up key attr name\n");
		MacOSError::throwMe(ortn);
	}

	UInt32 tags[2];
	tags[0] = printNameTag;
	tags[1] = labelHashTag;
	
	/* I don't know what the format field is for */
	SecKeychainAttributeInfo attrInfo;
	attrInfo.count = 2;
	attrInfo.tag = tags;
	attrInfo.format = NULL;	// ???
	
	/* FIXME header says this is an IN/OUT param, but it's not */
	SecKeychainAttributeList *attrList = NULL;
	
	ortn = SecKeychainItemCopyAttributesAndData(
		(SecKeychainItemRef)keyRef, 
		&attrInfo,
		NULL,			// itemClass
		&attrList, 
		NULL,			// don't need the data
		NULL);
	if(ortn) {
		p12ErrorLog("addSecKey: SecKeychainItemCopyAttributesAndData "
			"error\n");
		MacOSError::throwMe(ortn);		
	}
	
	/* Snag the attrs, convert to something useful */
	CFStringRef friendName = NULL;
	CFDataRef localKeyId = NULL;
	for(unsigned i=0; i<attrList->count; i++) {
		SecKeychainAttribute *attr = &attrList->attr[i];
		if(attr->tag == printNameTag) {
			friendName = CFStringCreateWithBytes(NULL, 
				(UInt8 *)attr->data, attr->length, 
				kCFStringEncodingUTF8,	false);
		}
		else if(attr->tag == labelHashTag) {
			localKeyId = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length);
		}
		else {
			p12ErrorLog("addSecKey: unexpected attr tag\n");
			MacOSError::throwMe(errSecParam);		
			
		}
	}
	
	/*
	 * Infer the CSP associated with this key.
	 * FIXME: this should be an attribute of the SecKeyRef itself,
	 * not inferred from the keychain it happens to be living on
	 * (SecKeyRefs should not have to be attached to Keychains at
	 * this point).
	 */
	SecKeychainRef kcRef;
	ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)keyRef, &kcRef);
	if(ortn) {
		p12ErrorLog("addSecKey: SecKeychainItemCopyKeychain returned %d\n", (int)ortn);
		MacOSError::throwMe(ortn);		
	}
	CSSM_CSP_HANDLE cspHand;
	ortn = SecKeychainGetCSPHandle(kcRef, &cspHand);
	if(ortn) {
		p12ErrorLog("addSecKey: SecKeychainGetCSPHandle returned %d\n", (int)ortn);
		MacOSError::throwMe(ortn);
	}
	CFRelease(kcRef);
	
	/* and the CSSM_KEY itself */
	const CSSM_KEY *cssmKey;
	ortn = SecKeyGetCSSMKey(keyRef, &cssmKey);
	if(ortn) {
		p12ErrorLog("addSecKey: SecKeyGetCSSMKey returned %d\n", (int)ortn);
		MacOSError::throwMe(ortn);		
	}
	
	/* Cook up a key bag and save it */
	P12KeyBag *keyBag = new P12KeyBag(cssmKey,
		cspHand, 
		friendName,	localKeyId, 
		NULL, 			// other attrs
		mCoder,
		keyRef);
	addKey(keyBag);
	SecKeychainItemFreeAttributesAndData(attrList, NULL);
	if(friendName) {
		CFRelease(friendName);
	}
	if(localKeyId) {
		CFRelease(localKeyId);
	}
}
/* 
 * Infer DescriptiveData (i.e., comment) from a SecKeyRef's PrintName
 * attribute.
 */
void impExpOpensshInferDescData(
	SecKeyRef keyRef,
	CssmOwnedData &descData)
{
	OSStatus ortn;
	SecKeychainAttributeInfo attrInfo;
	SecKeychainAttrType	attrType = kSecKeyPrintName;
	attrInfo.count = 1;
	attrInfo.tag = &attrType;
	attrInfo.format = NULL;	
	SecKeychainAttributeList *attrList = NULL;
	
	ortn = SecKeychainItemCopyAttributesAndData(
		(SecKeychainItemRef)keyRef, 
		&attrInfo,
		NULL,			// itemClass
		&attrList, 
		NULL,			// don't need the data
		NULL);
	if(ortn) {
		SecSSHDbg("SecKeychainItemCopyAttributesAndData returned %ld", (unsigned long)ortn);
		return;
	}
	/* subsequent errors to errOut: */
	SecKeychainAttribute *attr = attrList->attr;
		
	/*
	 * On a previous import, we would have set this to something like 
	 * "OpenSSHv2 Public Key: comment".
	 * We want to strip off everything up to the actual comment.
	 */
	unsigned toStrip = 0;	
	
	/* min length of attribute value for this code to be meaningful */
	unsigned len = strlen(SSHv2_PUB_KEY_NAME) + 1;	
	char *printNameStr = NULL;
	if(len < attr->length) {
		printNameStr = (char *)malloc(attr->length + 1);
		memmove(printNameStr, attr->data, attr->length);
		printNameStr[attr->length] = '\0';
		if(strstr(printNameStr, SSHv2_PUB_KEY_NAME) == printNameStr) {
			toStrip = strlen(SSHv2_PUB_KEY_NAME);
		}
		else if(strstr(printNameStr, SSHv1_PUB_KEY_NAME) == printNameStr) {
			toStrip = strlen(SSHv1_PUB_KEY_NAME);
		}
		else if(strstr(printNameStr, SSHv1_PRIV_KEY_NAME) == printNameStr) {
			toStrip = strlen(SSHv1_PRIV_KEY_NAME);
		}
		if(toStrip) {
			/* only strip if we have ": " after toStrip bytes */
			if((printNameStr[toStrip] == ':') && (printNameStr[toStrip+1] == ' ')) {
				toStrip += 2;
			}
		}
	}
	if(printNameStr) {
		free(printNameStr);
	}
	len = attr->length;

	unsigned char *attrVal;

	if(len < toStrip) {
		SecSSHDbg("impExpOpensshInferDescData: string parse screwup");
		goto errOut;
	}
	if(len > toStrip) {
		/* Normal case of stripping off leading header */
		len -= toStrip;
	}
	else {
		/* 
		 * If equal, then the attr value *is* "OpenSSHv2 Public Key: " with 
		 * no comment. Not sure how that could happen, but let's be careful.
		 */
		toStrip = 0;
	}
	
	attrVal = ((unsigned char *)attr->data) + toStrip;
	descData.copy(attrVal, len);
errOut:
	SecKeychainItemFreeAttributesAndData(attrList, NULL);
	return;
}