void StoreSecretAddress(Point address) { Point offset_point = depositdata[address]["offset_point"]; Point secret_address = address + offset_point; uint160 secret_address_hash = KeyHash(secret_address); uint160 full_secret_address_hash = FullKeyHash(secret_address); keydata[secret_address_hash]["pubkey"] = secret_address; keydata[full_secret_address_hash]["pubkey"] = secret_address; depositdata[secret_address_hash]["offset_point"] = offset_point; depositdata[secret_address_hash]["confirmed"] = true; depositdata[secret_address_hash]["address"] = secret_address; depositdata[full_secret_address_hash]["offset_point"] = offset_point; depositdata[full_secret_address_hash]["confirmed"] = true; depositdata[full_secret_address_hash]["address"] = secret_address; depositdata[secret_address]["public_address"] = address; }
// From http://tools.ietf.org/html/rfc6960#section-4.1.1: // "The hash shall be calculated over the value (excluding tag and length) of // the subject public key field in the issuer's certificate." // // From http://tools.ietf.org/html/rfc6960#appendix-B.1: // KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key // -- (i.e., the SHA-1 hash of the value of the // -- BIT STRING subjectPublicKey [excluding // -- the tag, length, and number of unused // -- bits] in the responder's certificate) static Result MatchKeyHash(TrustDomain& trustDomain, const SECItem& keyHash, const SECItem& subjectPublicKeyInfo, /*out*/ bool& match) { if (keyHash.len != TrustDomain::DIGEST_LENGTH) { return Fail(RecoverableError, SEC_ERROR_OCSP_MALFORMED_RESPONSE); } static uint8_t hashBuf[TrustDomain::DIGEST_LENGTH]; Result rv = KeyHash(trustDomain, subjectPublicKeyInfo, hashBuf, sizeof hashBuf); if (rv != Success) { return rv; } match = !memcmp(hashBuf, keyHash.data, keyHash.len); return Success; }
// From http://tools.ietf.org/html/rfc6960#section-4.1.1: // "The hash shall be calculated over the value (excluding tag and length) of // the subject public key field in the issuer's certificate." // // From http://tools.ietf.org/html/rfc6960#appendix-B.1: // KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key // -- (i.e., the SHA-1 hash of the value of the // -- BIT STRING subjectPublicKey [excluding // -- the tag, length, and number of unused // -- bits] in the responder's certificate) static Result MatchKeyHash(TrustDomain& trustDomain, Input keyHash, const Input subjectPublicKeyInfo, /*out*/ bool& match) { if (keyHash.GetLength() != TrustDomain::DIGEST_LENGTH) { return Result::ERROR_OCSP_MALFORMED_RESPONSE; } static uint8_t hashBuf[TrustDomain::DIGEST_LENGTH]; Result rv = KeyHash(trustDomain, subjectPublicKeyInfo, hashBuf, sizeof hashBuf); if (rv != Success) { return rv; } Input computed(hashBuf); match = InputsAreEqual(computed, keyHash); return Success; }
void DoScheduledPostDisclosureCheck(uint160 request_hash) { log_ << "DoScheduledPostDisclosureCheck: " << request_hash << "\n"; if (depositdata[request_hash]["cancelled"]) { log_ << request_hash << " has been cancelled\n"; return; } Point address = depositdata[request_hash]["address"]; log_ << "deposit address created: " << address << "\n"; uint160 address_hash = KeyHash(address); depositdata[address_hash]["address"] = address; log_ << "address for " << address_hash << " is " << address << "\n"; log_ << "keyhash_ is " << FullKeyHash(address) << "\n"; DepositAddressRequest request = msgdata[request_hash]["deposit_request"]; string address_string; if (request.currency_code != FLX) { Currency currency = flexnode.currencies[request.currency_code]; address_string = currency.crypto.PubKeyToAddress(address); } else { address_string = FlexAddressFromPubKey(address); } log_ << "final address is " << address_string << "\n"; CBitcoinAddress address_(address_string); CKeyID keyid; address_.GetKeyID(keyid); vch_t keydata_(BEGIN(keyid), END(keyid)); log_ << "keydata is " << keydata_ << "\n"; uint160 hash(keydata_); log_ << "hash is " << hash << "\n"; depositdata[hash]["address"] = address; CKeyID keyID(hash); log_ << "btc address is " << CBitcoinAddress(keyID).ToString() << "\n"; depositdata[address_hash]["confirmed"] = true; depositdata[FullKeyHash(address)]["confirmed"] = true; if (depositdata[address].HasProperty("offset_point")) { StoreSecretAddress(address); } }
Result CreateEncodedOCSPRequest(TrustDomain& trustDomain, const struct CertID& certID, /*out*/ uint8_t (&out)[OCSP_REQUEST_MAX_LENGTH], /*out*/ size_t& outLen) { // We do not add any extensions to the request. // RFC 6960 says "An OCSP client MAY wish to specify the kinds of response // types it understands. To do so, it SHOULD use an extension with the OID // id-pkix-ocsp-response." This use of MAY and SHOULD is unclear. MSIE11 // on Windows 8.1 does not include any extensions, whereas NSS has always // included the id-pkix-ocsp-response extension. Avoiding the sending the // extension is better for OCSP GET because it makes the request smaller, // and thus more likely to fit within the 255 byte limit for OCSP GET that // is specified in RFC 5019 Section 5. // Bug 966856: Add the id-pkix-ocsp-pref-sig-algs extension. // Since we don't know whether the OCSP responder supports anything other // than SHA-1, we have no choice but to use SHA-1 for issuerNameHash and // issuerKeyHash. static const uint8_t hashAlgorithm[11] = { 0x30, 0x09, // SEQUENCE 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJECT IDENTIFIER id-sha1 0x05, 0x00, // NULL }; static const uint8_t hashLen = TrustDomain::DIGEST_LENGTH; static const unsigned int totalLenWithoutSerialNumberData = 2 // OCSPRequest + 2 // tbsRequest + 2 // requestList + 2 // Request + 2 // reqCert (CertID) + sizeof(hashAlgorithm) // hashAlgorithm + 2 + hashLen // issuerNameHash + 2 + hashLen // issuerKeyHash + 2; // serialNumber (header) // The only way we could have a request this large is if the serialNumber was // ridiculously and unreasonably large. RFC 5280 says "Conforming CAs MUST // NOT use serialNumber values longer than 20 octets." With this restriction, // we allow for some amount of non-conformance with that requirement while // still ensuring we can encode the length values in the ASN.1 TLV structures // in a single byte. static_assert(totalLenWithoutSerialNumberData < OCSP_REQUEST_MAX_LENGTH, "totalLenWithoutSerialNumberData too big"); if (certID.serialNumber.GetLength() > OCSP_REQUEST_MAX_LENGTH - totalLenWithoutSerialNumberData) { return Result::ERROR_BAD_DER; } outLen = totalLenWithoutSerialNumberData + certID.serialNumber.GetLength(); uint8_t totalLen = static_cast<uint8_t>(outLen); uint8_t* d = out; *d++ = 0x30; *d++ = totalLen - 2u; // OCSPRequest (SEQUENCE) *d++ = 0x30; *d++ = totalLen - 4u; // tbsRequest (SEQUENCE) *d++ = 0x30; *d++ = totalLen - 6u; // requestList (SEQUENCE OF) *d++ = 0x30; *d++ = totalLen - 8u; // Request (SEQUENCE) *d++ = 0x30; *d++ = totalLen - 10u; // reqCert (CertID SEQUENCE) // reqCert.hashAlgorithm for (size_t i = 0; i < sizeof(hashAlgorithm); ++i) { *d++ = hashAlgorithm[i]; } // reqCert.issuerNameHash (OCTET STRING) *d++ = 0x04; *d++ = hashLen; Result rv = trustDomain.DigestBuf(certID.issuer, d, hashLen); if (rv != Success) { return rv; } d += hashLen; // reqCert.issuerKeyHash (OCTET STRING) *d++ = 0x04; *d++ = hashLen; rv = KeyHash(trustDomain, certID.issuerSubjectPublicKeyInfo, d, hashLen); if (rv != Success) { return rv; } d += hashLen; // reqCert.serialNumber (INTEGER) *d++ = 0x02; // INTEGER *d++ = static_cast<uint8_t>(certID.serialNumber.GetLength()); Reader serialNumber(certID.serialNumber); do { rv = serialNumber.Read(*d); if (rv != Success) { return rv; } ++d; } while (!serialNumber.AtEnd()); assert(d == out + totalLen); return Success; }
SECItem* CreateEncodedOCSPRequest(TrustDomain& trustDomain, PLArenaPool* arena, const struct CertID& certID) { if (!arena) { PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return nullptr; } // We do not add any extensions to the request. // RFC 6960 says "An OCSP client MAY wish to specify the kinds of response // types it understands. To do so, it SHOULD use an extension with the OID // id-pkix-ocsp-response." This use of MAY and SHOULD is unclear. MSIE11 // on Windows 8.1 does not include any extensions, whereas NSS has always // included the id-pkix-ocsp-response extension. Avoiding the sending the // extension is better for OCSP GET because it makes the request smaller, // and thus more likely to fit within the 255 byte limit for OCSP GET that // is specified in RFC 5019 Section 5. // Bug 966856: Add the id-pkix-ocsp-pref-sig-algs extension. // Since we don't know whether the OCSP responder supports anything other // than SHA-1, we have no choice but to use SHA-1 for issuerNameHash and // issuerKeyHash. static const uint8_t hashAlgorithm[11] = { 0x30, 0x09, // SEQUENCE 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJECT IDENTIFIER id-sha1 0x05, 0x00, // NULL }; static const uint8_t hashLen = TrustDomain::DIGEST_LENGTH; static const unsigned int totalLenWithoutSerialNumberData = 2 // OCSPRequest + 2 // tbsRequest + 2 // requestList + 2 // Request + 2 // reqCert (CertID) + PR_ARRAY_SIZE(hashAlgorithm) // hashAlgorithm + 2 + hashLen // issuerNameHash + 2 + hashLen // issuerKeyHash + 2; // serialNumber (header) // The only way we could have a request this large is if the serialNumber was // ridiculously and unreasonably large. RFC 5280 says "Conforming CAs MUST // NOT use serialNumber values longer than 20 octets." With this restriction, // we allow for some amount of non-conformance with that requirement while // still ensuring we can encode the length values in the ASN.1 TLV structures // in a single byte. if (certID.serialNumber.len > 127u - totalLenWithoutSerialNumberData) { PR_SetError(SEC_ERROR_BAD_DATA, 0); return nullptr; } uint8_t totalLen = static_cast<uint8_t>(totalLenWithoutSerialNumberData + certID.serialNumber.len); SECItem* encodedRequest = SECITEM_AllocItem(arena, nullptr, totalLen); if (!encodedRequest) { return nullptr; } uint8_t* d = encodedRequest->data; *d++ = 0x30; *d++ = totalLen - 2u; // OCSPRequest (SEQUENCE) *d++ = 0x30; *d++ = totalLen - 4u; // tbsRequest (SEQUENCE) *d++ = 0x30; *d++ = totalLen - 6u; // requestList (SEQUENCE OF) *d++ = 0x30; *d++ = totalLen - 8u; // Request (SEQUENCE) *d++ = 0x30; *d++ = totalLen - 10u; // reqCert (CertID SEQUENCE) // reqCert.hashAlgorithm for (size_t i = 0; i < PR_ARRAY_SIZE(hashAlgorithm); ++i) { *d++ = hashAlgorithm[i]; } // reqCert.issuerNameHash (OCTET STRING) *d++ = 0x04; *d++ = hashLen; if (trustDomain.DigestBuf(certID.issuer, d, hashLen) != SECSuccess) { return nullptr; } d += hashLen; // reqCert.issuerKeyHash (OCTET STRING) *d++ = 0x04; *d++ = hashLen; if (KeyHash(trustDomain, certID.issuerSubjectPublicKeyInfo, d, hashLen) != Success) { return nullptr; } d += hashLen; // reqCert.serialNumber (INTEGER) *d++ = 0x02; // INTEGER *d++ = static_cast<uint8_t>(certID.serialNumber.len); for (size_t i = 0; i < certID.serialNumber.len; ++i) { *d++ = certID.serialNumber.data[i]; } PR_ASSERT(d == encodedRequest->data + totalLen); return encodedRequest; }