Bug 1698017 - Update ODoH to draft 06, r=necko-reviewers,dragana

Differential Revision: https://phabricator.services.mozilla.com/D110915
This commit is contained in:
Kershaw Chang 2021-05-10 20:12:09 +00:00
Родитель ef16e154ae
Коммит 6d57ed5e05
7 изменённых файлов: 65 добавлений и 40 удалений

Просмотреть файл

@ -156,10 +156,10 @@ union NetAddr {
bool ToStringBuffer(char* buf, uint32_t bufSize) const;
};
#define ODOH_VERSION 0xff04
#define ODOH_VERSION 0xff06
static const char kODoHQuery[] = "odoh query";
static const char hODoHConfigID[] = "odoh key id";
static const char kODoHSecret[] = "odoh secret";
static const char kODoHResponse[] = "odoh response";
static const char kODoHKey[] = "odoh key";
static const char kODoHNonce[] = "odoh nonce";

Просмотреть файл

@ -1417,11 +1417,12 @@ static SECStatus HKDFExpand(PK11SymKey* aPrk, const SECItem* aInfo, int aLen,
return SECSuccess;
}
/* def decrypt_response_body(context, Q_plain, R_encrypted):
* key, nonce = derive_secrets(context, Q_plain)
* aad = 0x02 || 0x0000 // 0x0000 represents a 0-length KeyId
* R_plain, error = Open(key, nonce, aad, R_encrypted)
* return R_plain, error
/*
* def decrypt_response_body(context, Q_plain, R_encrypted, response_nonce):
* aead_key, aead_nonce = derive_secrets(context, Q_plain, response_nonce)
* aad = 0x02 || len(response_nonce) || response_nonce
* R_plain, error = Open(key, nonce, aad, R_encrypted)
* return R_plain, error
*/
bool ODoHDNSPacket::DecryptDNSResponse() {
ObliviousDoHMessage message;
@ -1434,33 +1435,39 @@ bool ODoHDNSPacket::DecryptDNSResponse() {
return false;
}
// KeyID for response should be empty.
if (!message.mKeyId.IsEmpty()) {
const unsigned int kResponseNonceLen = 16;
// KeyId is actually response_nonce
if (message.mKeyId.Length() != kResponseNonceLen) {
return false;
}
// def derive_secrets(context, Q_plain):
// odoh_secret = context.Export("odoh secret", 32)
// odoh_prk = Extract(Q_plain, odoh_secret)
// def derive_secrets(context, Q_plain, response_nonce):
// secret = context.Export("odoh response", Nk)
// salt = Q_plain || len(response_nonce) || response_nonce
// prk = Extract(salt, secret)
// key = Expand(odoh_prk, "odoh key", Nk)
// nonce = Expand(odoh_prk, "odoh nonce", Nn)
// return key, nonce
const SECItem kODoHSecretInfoItem = {
siBuffer, (unsigned char*)kODoHSecret,
static_cast<unsigned int>(strlen(kODoHSecret))};
const int kAes128GcmKeyLen = 16;
const int kAes128GcmNonceLen = 12;
const SECItem kODoHResponsetInfoItem = {
siBuffer, (unsigned char*)kODoHResponse,
static_cast<unsigned int>(strlen(kODoHResponse))};
const unsigned int kAes128GcmKeyLen = 16;
const unsigned int kAes128GcmNonceLen = 12;
PK11SymKey* tmp = nullptr;
SECStatus rv =
PK11_HPKE_ExportSecret(mContext, &kODoHSecretInfoItem, 32, &tmp);
SECStatus rv = PK11_HPKE_ExportSecret(mContext, &kODoHResponsetInfoItem,
kAes128GcmKeyLen, &tmp);
if (rv != SECSuccess) {
LOG(("ODoHDNSPacket::DecryptDNSResponse export secret failed"));
return false;
}
UniquePK11SymKey odohSecret(tmp);
SECItem* salt(::SECITEM_AllocItem(nullptr, nullptr, mPlainQuery->len));
SECItem* salt(::SECITEM_AllocItem(nullptr, nullptr,
mPlainQuery->len + 2 + kResponseNonceLen));
memcpy(salt->data, mPlainQuery->data, mPlainQuery->len);
NetworkEndian::writeUint16(&salt->data[mPlainQuery->len], kResponseNonceLen);
memcpy(salt->data + mPlainQuery->len + 2, message.mKeyId.Elements(),
kResponseNonceLen);
UniqueSECItem st(salt);
UniquePK11SymKey odohPrk;
rv = HKDFExtract(salt, odohSecret.get(), odohPrk);
@ -1498,8 +1505,13 @@ bool ODoHDNSPacket::DecryptDNSResponse() {
return false;
}
// aad = 0x02 || 0x0000
uint8_t aad[] = {0x2, 0, 0};
// aad = 0x02 || len(response_nonce) || response_nonce
SECItem* aadItem(
::SECITEM_AllocItem(nullptr, nullptr, 1 + 2 + kResponseNonceLen));
aadItem->data[0] = ODOH_RESPONSE;
NetworkEndian::writeUint16(&aadItem->data[1], kResponseNonceLen);
memcpy(&aadItem->data[3], message.mKeyId.Elements(), kResponseNonceLen);
UniqueSECItem aad(aadItem);
SECItem paramItem;
CK_GCM_PARAMS param;
@ -1507,8 +1519,8 @@ bool ODoHDNSPacket::DecryptDNSResponse() {
param.ulIvLen = derivedItem->len;
param.ulIvBits = param.ulIvLen * 8;
param.ulTagBits = 16 * 8;
param.pAAD = (CK_BYTE_PTR)aad;
param.ulAADLen = 3;
param.pAAD = (CK_BYTE_PTR)aad->data;
param.ulAADLen = aad->len;
paramItem.type = siBuffer;
paramItem.data = (unsigned char*)(&param);
@ -1519,7 +1531,8 @@ bool ODoHDNSPacket::DecryptDNSResponse() {
MAX_SIZE, message.mEncryptedMessage.Elements(),
message.mEncryptedMessage.Length());
if (rv != SECSuccess) {
LOG(("ODoHDNSPacket::DecryptDNSResponse decrypt failed"));
LOG(("ODoHDNSPacket::DecryptDNSResponse decrypt failed %d",
PORT_GetError()));
return false;
}

Просмотреть файл

@ -506,7 +506,6 @@ skip-if = os == "android" || !debug
[test_SuperfluousAuth.js]
[test_odoh.js]
run-sequentially = node server exceptions dont replay well
skip-if = true # Bug 1709551
[test_trr_confirmation.js]
skip-if = os =='android' || socketprocess_networking # confirmation state isn't passed cross-process
run-sequentially = node server exceptions dont replay well

Просмотреть файл

@ -14,11 +14,12 @@ default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = "0.2.63"
odoh-rs = "=0.1.8"
hpke = "0.4.3"
odoh-rs = "=0.1.10"
hpke = "=0.5.0"
js-sys = "0.3"
hex = "0.4"
futures = "0.3.1"
rand = "=0.7"
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires

Просмотреть файл

@ -93,22 +93,22 @@ module.exports.__wbg_log_b3f203d9e6882397 = function(arg0, arg1) {
console.log(getStringFromWasm0(arg0, arg1));
};
module.exports.__wbg_buffer_bc64154385c04ac4 = function(arg0) {
module.exports.__wbg_buffer_ebc6c8e75510eae3 = function(arg0) {
var ret = getObject(arg0).buffer;
return addHeapObject(ret);
};
module.exports.__wbg_newwithbyteoffsetandlength_3c8748473807c7cf = function(arg0, arg1, arg2) {
module.exports.__wbg_newwithbyteoffsetandlength_ca3d3d8811ecb569 = function(arg0, arg1, arg2) {
var ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0);
return addHeapObject(ret);
};
module.exports.__wbg_new_22a33711cf65b661 = function(arg0) {
module.exports.__wbg_new_135e963dedf67b22 = function(arg0) {
var ret = new Uint8Array(getObject(arg0));
return addHeapObject(ret);
};
module.exports.__wbg_newwithlength_48451d71403bfede = function(arg0) {
module.exports.__wbg_newwithlength_78dc302d31527318 = function(arg0) {
var ret = new Uint8Array(arg0 >>> 0);
return addHeapObject(ret);
};

Двоичные данные
testing/xpcshell/odoh-wasm/pkg/odoh_wasm_bg.wasm

Двоичный файл не отображается.

Просмотреть файл

@ -21,6 +21,11 @@ pub type Kem = X25519HkdfSha256;
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
pub const ODOH_VERSION: u16 = 0xff06;
const KEM_ID: u16 = 0x0020;
const KDF_ID: u16 = 0x0001;
const AEAD_ID: u16 = 0x0001;
// random bytes, should be 32 bytes for X25519 keys
pub const IKM: &str = "871389a8727130974e3eb3ee528d440a871389a8727130974e3eb3ee528d440a";
@ -53,9 +58,9 @@ fn generate_key_pair() -> ObliviousDoHKeyPair {
let (secret_key, public_key) = Kem::derive_keypair(&ikm_bytes);
let public_key_bytes = public_key.to_bytes().to_vec();
let odoh_public_key = ObliviousDoHConfigContents {
kem_id: 0x0020,
kdf_id: 0x0001,
aead_id: 0x0001,
kem_id: KEM_ID,
kdf_id: KDF_ID,
aead_id: AEAD_ID,
public_key: public_key_bytes,
};
ObliviousDoHKeyPair {
@ -70,11 +75,11 @@ pub fn get_odoh_config() -> js_sys::Uint8Array {
let public_key_bytes = key_pair.public_key.public_key;
let length_bytes = (public_key_bytes.len() as u16).to_be_bytes();
let odoh_config_length = 12 + public_key_bytes.len();
let version = 0xff04;
let version = ODOH_VERSION;
let odoh_contents_length = 8 + public_key_bytes.len();
let kem_id = 0x0020; // DHKEM(X25519, HKDF-SHA256)
let kdf_id = 0x0001; // KDF(SHA-256)
let aead_id = 0x0001; // AEAD(AES-GCM-128)
let kem_id = KEM_ID; // DHKEM(X25519, HKDF-SHA256)
let kdf_id = KDF_ID; // KDF(SHA-256)
let aead_id = AEAD_ID; // AEAD(AES-GCM-128)
let mut result = vec![];
result.extend(&((odoh_config_length as u16).to_be_bytes()));
result.extend(&((version as u16).to_be_bytes()));
@ -123,15 +128,22 @@ pub fn create_response(
unsafe {
if let Some(body) = &QUERY_BODY {
if let Some(secret) = &SERVER_SECRET {
// random bytes
let nonce = vec![0x1b, 0xff, 0xfd, 0xff, 0x1a, 0xff, 0xff, 0xff,
0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xe];
let result = executor::block_on(create_response_msg(
&secret,
&response,
None,
Some(nonce),
&body,
));
let generated_response = match result {
Ok(r) => r,
Err(_) => return js_sys::Uint8Array::new_with_length(0),
Err(_) => {
console_log!("create_response_msg failed!");
return js_sys::Uint8Array::new_with_length(0);
}
};
QUERY_BODY = None;