/// <summary> /// Given a first message in the Edhoc protocol, parse the message into pieces /// and fill in the data struture elements to continue processing. /// Throw an exception on failures. /// </summary> /// <param name="msgData"></param> /// <returns></returns> public static EdhocResponder ParseMessage1(byte[] msgData) { EdhocResponder edhoc = new EdhocResponder(); CBORObject msg = CBORObject.DecodeFromBytes(msgData); if (msg.Type != CBORType.Array) { throw new Exception("Invalid message"); } if (msg[0].AsInt32() == 1) { edhoc._fSymmetricSecret = false; } else if (msg[0].AsInt32() == 4) { edhoc._fSymmetricSecret = true; } else { throw new Exception("Invalid Message"); } // Fill in "their" data into the different arrays edhoc._Messages[0] = msgData; // message_1 edhoc._SessionId[1] = msg[1].GetByteString(); edhoc._Nonce[1] = msg[2].GetByteString(); edhoc._Keys[1] = new OneKey(msg[3]); // Their one time key edhoc._algKeyAgree = _SelectAlgorithm(msg[4], new CBORObject[] { AlgorithmValues.ECDH_SS_HKDF_256 }); edhoc._algAEAD = _SelectAlgorithm(msg[5], new CBORObject[] { AlgorithmValues.AES_CCM_64_64_128 }); if (!edhoc._fSymmetricSecret) { edhoc._algSign = _SelectAlgorithm(msg[6], new CBORObject[] { AlgorithmValues.ECDSA_256 }); } else { edhoc._kid[1] = msg[6]; } edhoc._Keys[0] = OneKey.GenerateKey(null, edhoc._Keys[1][CoseKeyKeys.KeyType], "X25519" /*edhoc._Keys[1][CoseKeyParameterKeys.EC_Curve].AsString()*/); #if true edhoc._SessionId[0] = new byte[2]; edhoc._random.NextBytes(edhoc._SessionId[0]); edhoc._Nonce[0] = new byte[8]; edhoc._random.NextBytes(edhoc._Nonce[0]); #else edhoc._SessionId[0] = Encoding.UTF8.GetBytes("Kid Svr"); edhoc._Nonce[0] = Encoding.UTF8.GetBytes("Server Nonce"); #endif MessageList.Add(new ListKey(edhoc._SessionId[0]), edhoc); return(edhoc); }
static public EdhocResponder ParseMessage3(byte[] msgData, KeySet serverKeys) { CBORObject algVerify = null; CBORObject msg = CBORObject.DecodeFromBytes(msgData); if (msg.Type != CBORType.Array) { throw new Exception("Invalid message"); } EdhocResponder edhoc = MessageList[new ListKey(msg[1].GetByteString())]; edhoc._Messages[2] = msgData; if (edhoc._fSymmetricSecret) { if (msg[0].AsInt16() != 6) { throw new Exception("Invalid Message"); } } else { if (msg[0].AsInt16() != 3) { throw new Exception("Invalid Message"); } } Encrypt0Message enc0 = (Encrypt0Message)Com.AugustCellars.COSE.Message.DecodeFromBytes(msg[2].GetByteString(), Tags.Encrypt0); msg.Remove(msg[2]); byte[] data_3 = msg.EncodeToBytes(); byte[] aad_3 = ConcatenateAndHash(new byte[][] { edhoc._LastMessageAuthenticator, data_3 }, edhoc._MessageDigest); byte[][] useKeys = _DeriveKeys(edhoc._Keys, edhoc._SecretSalt, aad_3, edhoc._algAEAD); byte[] encKey = useKeys[0]; enc0.AddAttribute(HeaderKeys.Algorithm, edhoc._algAEAD, Attributes.DO_NOT_SEND); enc0.AddAttribute(HeaderKeys.IV, CBORObject.FromObject(useKeys[1]), Attributes.DO_NOT_SEND); enc0.SetExternalData(aad_3); byte[] body = enc0.Decrypt(encKey); if (!edhoc._fSymmetricSecret) { CBORObject encBody = CBORObject.DecodeFromBytes(body); Sign1Message sign1 = (Sign1Message)Com.AugustCellars.COSE.Message.DecodeFromBytes(encBody[0].GetByteString(), Tags.Sign1); sign1.AddAttribute(HeaderKeys.Algorithm, edhoc._algSign, Attributes.DO_NOT_SEND); CBORObject kidObject = sign1.FindAttribute(HeaderKeys.KeyId); byte[] kid = null; if (kidObject != null) { kid = kidObject.GetByteString(); } sign1.SetExternalData(aad_3); KeySet keys = new KeySet(); foreach (OneKey sigKey in serverKeys) { if (sigKey.HasKid(kid)) { keys.AddKey(sigKey); } } List <OneKey> ks = new List <OneKey>(); List <OneKey> ks2 = ks.Where(f => f.HasKid(kid)).ToList(); OneKey signingKey = null; foreach (OneKey sigKey in keys) { try { sign1.Validate(sigKey); signingKey = sigKey; } catch (Exception) { // nop; } } if (signingKey == null) { throw new Exception("Unable to complete - no signing key found"); } } else { // body is the EXT_3 value } edhoc._LastMessageAuthenticator = ConcatenateAndHash(new byte[][] { edhoc._LastMessageAuthenticator, msgData }, edhoc._MessageDigest); return(edhoc); }
protected override void DoPost(CoapExchange exchange) { byte[] body = exchange.Request.Payload; EdhocResponder edhoc; try { switch (body[1] & 0xf) { case 1: edhoc = EdhocResponder.ParseMessage1(body); edhoc.SigningKey = _signKey; body = edhoc.CreateMessage2(); exchange.Respond(CoAP.StatusCode.Changed, body); break; case 4: edhoc = EdhocResponder.ParseMessage1(body); OneKey y = null; foreach (OneKey x in _allKeys) { if (x.ContainsName(CoseKeyKeys.KeyIdentifier)) { if (x.HasKid(edhoc.KeyIdentifier)) { if (y != null) { exchange.Respond(CoAP.StatusCode.BadRequest); return; } y = new OneKey(x.AsCBOR()); } } } if (y == null) { exchange.Respond(CoAP.StatusCode.BadRequest); return; } if (!y[CoseKeyKeys.KeyType].Equals(GeneralValues.KeyType_Octet)) { exchange.Respond(CoAP.StatusCode.BadRequest); return; } edhoc.SharedSecret = y; body = edhoc.CreateMessage2(); exchange.Respond(CoAP.StatusCode.Changed, body); break; case 3: edhoc = EdhocResponder.ParseMessage3(body, _allKeys); exchange.Respond(StatusCode.Changed); OSCOAP.SecurityContext ctx = edhoc.CreateSecurityContext(); OSCOAP.SecurityContextSet.AllContexts.Add(ctx); break; case 6: edhoc = EdhocResponder.ParseMessage3(body, _allKeys); exchange.Respond(CoAP.StatusCode.Changed); OSCOAP.SecurityContext ctx2 = edhoc.CreateSecurityContext(); OSCOAP.SecurityContextSet.AllContexts.Add(ctx2); break; default: exchange.Respond(CoAP.StatusCode.BadRequest); break; } } catch (Exception e) { CBORObject obj = CBORObject.NewArray(); obj.Add(0); obj.Add(e.ToString()); exchange.Respond(CoAP.StatusCode.Content, obj.EncodeToBytes()); } }