+
+/* Fill out a CSSM_DATA with the subset of public key bytes from the given
+ * CSSM_KEY_PTR which should be hashed to produce the issuerKeyHash field
+ * of a CertID in an OCSP request.
+ *
+ * For RSA keys, this simply copies the input key pointer and length.
+ * For EC keys, we need to further deconstruct the SubjectPublicKeyInfo
+ * to obtain the key bytes (i.e. curve point) for hashing.
+ *
+ * Returns CSSM_OK on success, or non-zero error if the bytes could not
+ * be retrieved.
+ */
+CSSM_RETURN ocspdGetPublicKeyBytes(
+ SecAsn1CoderRef coder, // optional
+ CSSM_KEY_PTR publicKey, // input public key
+ CSSM_DATA &publicKeyBytes) // filled in by this function
+{
+ CSSM_RETURN crtn = CSSM_OK;
+ SecAsn1CoderRef _coder = NULL;
+
+ if(publicKey == NULL) {
+ crtn = CSSMERR_CSP_INVALID_KEY_POINTER;
+ goto exit;
+ }
+
+ if(coder == NULL) {
+ crtn = SecAsn1CoderCreate(&_coder);
+ if(crtn) {
+ goto exit;
+ }
+ coder = _coder;
+ }
+
+ publicKeyBytes.Length = publicKey->KeyData.Length;
+ publicKeyBytes.Data = publicKey->KeyData.Data;
+
+ if(publicKey->KeyHeader.AlgorithmId == CSSM_ALGID_ECDSA) {
+ /*
+ * For an EC key, publicKey->KeyData is a SubjectPublicKeyInfo
+ * ASN.1 sequence that includes the algorithm identifier.
+ * We only want to return the bit string portion of the key here.
+ */
+ SecAsn1PubKeyInfo pkinfo;
+ memset(&pkinfo, 0, sizeof(pkinfo));
+ if(SecAsn1Decode(coder,
+ publicKey->KeyData.Data,
+ publicKey->KeyData.Length,
+ kSecAsn1SubjectPublicKeyInfoTemplate,
+ &pkinfo) == 0) {
+ if(pkinfo.subjectPublicKey.Length &&
+ pkinfo.subjectPublicKey.Data) {
+ publicKeyBytes.Length = pkinfo.subjectPublicKey.Length >> 3;
+ publicKeyBytes.Data = pkinfo.subjectPublicKey.Data;
+ /*
+ * Important: if we allocated the SecAsn1Coder, the memory
+ * being pointed to by pkinfo.subjectPublicKey.Data will be
+ * deallocated when the coder is released below. We want to
+ * point to the identical data inside the caller's public key,
+ * now that the decoder has identified it for us.
+ */
+ if(publicKeyBytes.Length <= publicKey->KeyData.Length) {
+ publicKeyBytes.Data = (uint8*)((uintptr_t)publicKey->KeyData.Data +
+ (publicKey->KeyData.Length - publicKeyBytes.Length));
+ goto exit;
+ }
+ /* intentional fallthrough to error exit */
+ }
+ ocspdErrorLog("ocspdGetPublicKeyBytes: invalid SecAsn1PubKeyInfo\n");
+ crtn = CSSMERR_CSP_INVALID_KEY_POINTER;
+ }
+ else {
+ /* Unable to decode using kSecAsn1SubjectPublicKeyInfoTemplate.
+ * This may or may not be an error; just return the unchanged key.
+ */
+ ocspdErrorLog("ocspdGetPublicKeyBytes: unable to decode SubjectPublicKeyInfo\n");
+ }
+ }
+
+exit:
+ if(_coder) {
+ SecAsn1CoderRelease(_coder);
+ }
+ return crtn;
+}