Protocol: freeze device proof and browser CSRF contracts
This commit is contained in:
@@ -4,6 +4,7 @@ package protocol
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -5564,6 +5565,30 @@ func EncodeVersionNegotiation(value VersionNegotiation) ([]byte, error) {
|
||||
return json.Marshal(value)
|
||||
}
|
||||
|
||||
func DeviceRegistrationProofTranscript(serverID, principalID, deviceID, challenge []byte, expiryUnixMilliseconds int64) ([]byte, error) {
|
||||
for _, value := range []struct {
|
||||
field string
|
||||
bytes []byte
|
||||
length int
|
||||
}{{"server_id", serverID, 16}, {"principal_id", principalID, 16}, {"device_id", deviceID, 16}, {"challenge", challenge, 32}} {
|
||||
if len(value.bytes) != value.length {
|
||||
return nil, ValidationError{Violations: []FieldViolation{{Field: value.field, Code: "invalid_length"}}}
|
||||
}
|
||||
}
|
||||
if expiryUnixMilliseconds < 0 {
|
||||
return nil, ValidationError{Violations: []FieldViolation{{Field: "expiry_unix_milliseconds", Code: "minimum"}}}
|
||||
}
|
||||
transcript := make([]byte, 0, 112)
|
||||
transcript = append(transcript, "versevdi-device-proof-v1"...)
|
||||
transcript = append(transcript, serverID...)
|
||||
transcript = append(transcript, principalID...)
|
||||
transcript = append(transcript, deviceID...)
|
||||
transcript = append(transcript, challenge...)
|
||||
var expiry [8]byte
|
||||
binary.BigEndian.PutUint64(expiry[:], uint64(expiryUnixMilliseconds))
|
||||
return append(transcript, expiry[:]...), nil
|
||||
}
|
||||
|
||||
var ErrNoCapabilityOverlap = errors.New("no capability overlap")
|
||||
|
||||
func IntersectCapabilityProfiles(profiles ...CapabilityProfile) (CapabilityProfile, error) {
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
"3"
|
||||
]
|
||||
},
|
||||
"generator_sha256": "8a153cf1e99682d010ff91c754ef056c64aece8f8bbca0ca58f8eef2b9039119",
|
||||
"generator_sha256": "00c1905fc611ca9e226cd90da761b48b8e203734b10542befea397a30082d360",
|
||||
"protocol_version": "1.0.0",
|
||||
"schema_sha256": "dea3dd210c53d5a2d37050dd6afd8b0ac5bb8edcb7ab25a02e4026489ce8a00f"
|
||||
}
|
||||
|
||||
@@ -1976,6 +1976,21 @@ impl VersionNegotiation {
|
||||
pub fn features(&self) -> &Vec<String> { &self.features }
|
||||
}
|
||||
|
||||
pub fn device_registration_proof_transcript(server_id: &[u8], principal_id: &[u8], device_id: &[u8], challenge: &[u8], expiry_unix_milliseconds: i64) -> Result<Vec<u8>, ValidationError> {
|
||||
for (field, value, length) in [("server_id", server_id, 16), ("principal_id", principal_id, 16), ("device_id", device_id, 16), ("challenge", challenge, 32)] {
|
||||
if value.len() != length { return Err(ValidationError::new(field, "invalid_length")); }
|
||||
}
|
||||
if expiry_unix_milliseconds < 0 { return Err(ValidationError::new("expiry_unix_milliseconds", "minimum")); }
|
||||
let mut transcript = Vec::with_capacity(112);
|
||||
transcript.extend_from_slice(b"versevdi-device-proof-v1");
|
||||
transcript.extend_from_slice(server_id);
|
||||
transcript.extend_from_slice(principal_id);
|
||||
transcript.extend_from_slice(device_id);
|
||||
transcript.extend_from_slice(challenge);
|
||||
transcript.extend_from_slice(&(expiry_unix_milliseconds as u64).to_be_bytes());
|
||||
Ok(transcript)
|
||||
}
|
||||
|
||||
pub fn intersect_capability_profiles(profiles: &[CapabilityProfile]) -> Result<CapabilityProfile, ValidationError> {
|
||||
let mut selected = profiles.first().ok_or_else(|| ValidationError::new("capabilities", "no_overlap"))?.clone();
|
||||
selected.validate().map_err(|_| ValidationError::new("capabilities", "no_overlap"))?;
|
||||
|
||||
@@ -2583,6 +2583,21 @@ public struct VersionNegotiation: Codable, Equatable {
|
||||
public func encodeJSON() throws -> Data { try validate(); return try JSONEncoder().encode(self) }
|
||||
}
|
||||
|
||||
public func deviceRegistrationProofTranscript(serverID: Data, principalID: Data, deviceID: Data, challenge: Data, expiryUnixMilliseconds: Int64) throws -> Data {
|
||||
for (field, value, length) in [("server_id", serverID, 16), ("principal_id", principalID, 16), ("device_id", deviceID, 16), ("challenge", challenge, 32)] {
|
||||
if value.count != length { throw ContractValidationError(field: field, code: "invalid_length") }
|
||||
}
|
||||
if expiryUnixMilliseconds < 0 { throw ContractValidationError(field: "expiry_unix_milliseconds", code: "minimum") }
|
||||
var transcript = Data("versevdi-device-proof-v1".utf8)
|
||||
transcript.append(serverID)
|
||||
transcript.append(principalID)
|
||||
transcript.append(deviceID)
|
||||
transcript.append(challenge)
|
||||
var expiry = UInt64(expiryUnixMilliseconds).bigEndian
|
||||
Swift.withUnsafeBytes(of: &expiry) { transcript.append(contentsOf: $0) }
|
||||
return transcript
|
||||
}
|
||||
|
||||
public extension TunnelAdmissionRequest {
|
||||
func deviceAdmissionTranscript() -> Data {
|
||||
var fields = [sessionId, gatewayId, audience, grant, String(reconnectSequence), clientNonce, capabilities.transport, capabilities.framing, capabilities.media, capabilities.audio, capabilities.sourceRateControl, String(capabilities.clientDecode.count)]
|
||||
|
||||
Reference in New Issue
Block a user