protected override void DoPost(CoapExchange exchange) { try { Request request = exchange.Request; CBORObject obj = CBORObject.DecodeFromBytes(request.Payload); exchange.Accept(); String uri = obj[0].AsString(); byte[] key = obj[1].GetByteString(); List <SecurityContext> contexts = SecurityContextSet.AllContexts.FindByKid(key); if (contexts.Count == 0) { exchange.Respond(StatusCode.BadRequest, "No matching key identifier found"); return; } Codec.IMessageDecoder me = Spec.Default.NewMessageDecoder(obj[2].GetByteString()); Request newRequest = me.DecodeRequest(); newRequest.URI = new System.Uri(uri); newRequest.OscoapContext = contexts[0]; newRequest.Send(); Response response = newRequest.WaitForResponse(); exchange.Respond(response); } catch (Exception e) { exchange.Respond(StatusCode.BadRequest, e.ToString()); } }
public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response) { if (response.HasOption(OptionType.Oscoap)) { Option op = response.GetFirstOption(OptionType.Oscoap); if (exchange.OscoapContext == null) { return; } SecurityContext ctx = exchange.OscoapContext; bool fServerIv = true; Encrypt0Message msg = Uncompress(op.RawValue); if (msg == null) { return; } msg.SetEncryptedContent(response.Payload); SecurityContext.EntityContext recip = ctx.Recipient; if (recip == null) { if (ctx.GroupId == null) { // This is not currently a valid state to be in return; } CBORObject kid = msg.FindAttribute(HeaderKeys.KeyId); if (kid == null) { // this is not currently a valid state to be in return; } recip = ctx.Recipients[kid.GetByteString()]; if (recip == null) { // M00TODO - deal with asking the user for a recipient structure at this point. return; } } if (msg.FindAttribute(HeaderKeys.PartialIV) == null) { msg.AddAttribute(HeaderKeys.PartialIV, CBORObject.FromObject(ctx.Sender.PartialIV), Attributes.DO_NOT_SEND); fServerIv = false; } byte[] partialIV = msg.FindAttribute(HeaderKeys.PartialIV).GetByteString(); byte[] seqNoArray = new byte[8]; Array.Copy(partialIV, 0, seqNoArray, 8 - partialIV.Length, partialIV.Length); if (BitConverter.IsLittleEndian) { Array.Reverse(seqNoArray); } Int64 seqNo = BitConverter.ToInt64(seqNoArray, 0); if (fServerIv) { if (_replayWindow && recip.ReplayWindow.HitTest(seqNo)) { return; } } msg.AddAttribute(HeaderKeys.Algorithm, recip.Algorithm, Attributes.DO_NOT_SEND); CBORObject fullIV; if (fServerIv) { fullIV = recip.GetIV(partialIV); } else { fullIV = ctx.Sender.GetIV(partialIV); } msg.AddAttribute(HeaderKeys.IV, fullIV, Attributes.DO_NOT_SEND); // build aad CBORObject aad = CBORObject.NewArray(); aad.Add(1); aad.Add(CBORObject.NewArray()); aad[1].Add(recip.Algorithm); aad.Add(ctx.Sender.Id); aad.Add(ctx.Sender.PartialIV); aad.Add(CBORObject.FromObject(new byte[0])); // OPTIONS if (ctx.GroupId != null) { aad.Add(ctx.GroupId); } msg.SetExternalData(aad.EncodeToBytes()); _Log.Info(m => m($"fServerIv = {fServerIv}")); _Log.Info(m => m("ReceiveResponse: AAD = " + BitConverter.ToString(aad.EncodeToBytes()))); _Log.Info(m => m($"ReceiveResponse: IV = {BitConverter.ToString(fullIV.GetByteString())}")); _Log.Info(m => m($"ReceiveResponse: Key = {BitConverter.ToString(recip.Key)}")); byte[] payload = msg.Decrypt(recip.Key); recip.ReplayWindow.SetHit(seqNo); byte[] rgb = new byte[payload.Length + _FixedHeader.Length - 1]; Array.Copy(_FixedHeader, rgb, _FixedHeader.Length); Array.Copy(payload, 1, rgb, _FixedHeader.Length, payload.Length - 1); rgb[1] = payload[0]; Codec.IMessageDecoder me = Spec.NewMessageDecoder(rgb); Response decryptedReq = me.DecodeResponse(); response.Payload = decryptedReq.Payload; response.StatusCode = decryptedReq.StatusCode; RestoreOptions(response, decryptedReq); } base.ReceiveResponse(nextLayer, exchange, response); }
/// <inheritdoc /> public override void ReceiveRequest(INextLayer nextLayer, Exchange exchange, Request request) { if (!request.HasOption(OptionType.Oscoap)) { base.ReceiveRequest(nextLayer, exchange, request); return; } Response response; try { Option op = request.GetFirstOption(OptionType.Oscoap); request.RemoveOptions(OptionType.Oscoap); _Log.Info(m => m("Incoming Request: {0}", Util.Utils.ToString(request))); Encrypt0Message msg = Uncompress(op.RawValue); if (msg == null) { // Only bother to reply to CON messages if (request.Type == MessageType.CON) { response = new Response(StatusCode.BadOption) { PayloadString = "Unable to decompress" }; exchange.SendResponse(response); } return; } msg.SetEncryptedContent(request.Payload); List <SecurityContext> contexts = new List <SecurityContext>(); SecurityContext ctx = null; CBORObject kid; // We may know the context because it is a follow up on a conversation - // In which case we can just use the same one. // M00BUG - Multicast problem of recipient ID? CBORObject gid = null; if (exchange.OscoapContext != null) { contexts.Add(exchange.OscoapContext); if (exchange.OscoapContext.GroupId != null) { gid = CBORObject.FromObject(exchange.OscoapContext.GroupId); } kid = CBORObject.FromObject(exchange.OscoapSenderId); } else { gid = msg.FindAttribute(CBORObject.FromObject("gid")); kid = msg.FindAttribute(HeaderKeys.KeyId); if (kid == null) { exchange.SendResponse(new Response(StatusCode.BadRequest)); return; } if (gid != null) { contexts = SecurityContextSet.AllContexts.FindByGroupId(gid.GetByteString()); } else { contexts = SecurityContextSet.AllContexts.FindByKid(kid.GetByteString()); } if (contexts.Count == 0) { response = new Response(StatusCode.Unauthorized) { PayloadString = "No Context Found - 1" }; exchange.SendResponse(response); return; // Ignore messages that have no known security context. } } byte[] partialIV = msg.FindAttribute(HeaderKeys.PartialIV).GetByteString(); // Build AAD CBORObject aad = CBORObject.NewArray(); aad.Add(CBORObject.FromObject(1)); // M00BUG aad.Add(CBORObject.NewArray()); // Array place holder aad[1].Add(CBORObject.FromObject(0)); // Place holder for algorithm aad.Add(CBORObject.FromObject(kid)); aad.Add(CBORObject.FromObject(partialIV)); aad.Add(CBORObject.FromObject(new byte[0])); // encoded I options if (gid != null) { aad.Add(gid); } byte[] payload = null; byte[] seqNoArray = new byte[8]; Array.Copy(partialIV, 0, seqNoArray, 8 - partialIV.Length, partialIV.Length); if (BitConverter.IsLittleEndian) { Array.Reverse(seqNoArray); } Int64 seqNo = BitConverter.ToInt64(seqNoArray, 0); String responseString = "General decrypt failure"; foreach (SecurityContext context in contexts) { SecurityContext.EntityContext recip = context.Recipient; if (recip == null) { if (kid == null) { continue; } recip = context.Recipients[kid.GetByteString()]; if (recip == null) { continue; } } if (_replayWindow && recip.ReplayWindow.HitTest(seqNo)) { _Log.Info(m => m("Hit test on {0} failed", seqNo)); responseString = "Hit test - duplicate"; continue; } aad[1][0] = recip.Algorithm; if (_Log.IsInfoEnabled) { _Log.Info("AAD = " + BitConverter.ToString(aad.EncodeToBytes())); _Log.Info("IV = " + BitConverter.ToString(recip.GetIV(partialIV).GetByteString())); _Log.Info("Key = " + BitConverter.ToString(recip.Key)); } msg.SetExternalData(aad.EncodeToBytes()); msg.AddAttribute(HeaderKeys.Algorithm, recip.Algorithm, Attributes.DO_NOT_SEND); msg.AddAttribute(HeaderKeys.IV, recip.GetIV(partialIV), Attributes.DO_NOT_SEND); try { ctx = context; payload = msg.Decrypt(recip.Key); recip.ReplayWindow.SetHit(seqNo); } catch (Exception e) { if (_Log.IsInfoEnabled) { _Log.Info("--- ", e); } ctx = null; } if (ctx != null) { break; } } if (ctx == null) { if (request.Type == MessageType.CON) { response = new Response(StatusCode.BadRequest) { PayloadString = responseString }; exchange.SendResponse(response); } return; } exchange.OscoapContext = ctx; // So we know it on the way back. request.OscoapContext = ctx; exchange.OscoapSequenceNumber = partialIV; exchange.OscoapSenderId = kid.GetByteString(); byte[] newRequestData = new byte[payload.Length + _FixedHeader.Length - 1]; Array.Copy(_FixedHeader, newRequestData, _FixedHeader.Length); Array.Copy(payload, 1, newRequestData, _FixedHeader.Length, payload.Length - 1); newRequestData[1] = payload[0]; Codec.IMessageDecoder me = Spec.NewMessageDecoder(newRequestData); Request newRequest = me.DecodeRequest(); // Update headers is a pain RestoreOptions(request, newRequest); request.Method = newRequest.Method; if (_Log.IsInfoEnabled) { // log.Info(String.Format("Secure message post = " + Util.Utils.ToString(request))); } // We may want a new exchange at this point if it relates to a new message for blockwise. if (request.HasOption(OptionType.Block2)) { Exchange.KeyUri keyUri = new Exchange.KeyUri(request.URI, null, request.Source); BlockHolder block; _ongoingExchanges.TryGetValue(keyUri, out block); if (block != null) { block.RestoreTo(exchange); } } request.Payload = newRequest.Payload; } catch (Exception e) { _Log.Error("OSCOAP Layer: reject message because ", e); exchange.OscoapContext = null; if (request.Type == MessageType.CON) { response = new Response(StatusCode.Unauthorized) { Payload = Encoding.UTF8.GetBytes("Error is " + e.Message) }; exchange.SendResponse(response); } // Ignore messages that we cannot decrypt. return; } base.ReceiveRequest(nextLayer, exchange, request); }
public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response) { if (response.HasOption(OptionType.Oscoap)) { Option op = response.GetFirstOption(OptionType.Oscoap); if (exchange.OscoreContext == null) { return; } _Log.Info($"Incoming message for OSCORE\n{Utils.ToString(response)}"); SecurityContext ctx = exchange.OscoreContext; bool fServerIv = true; Encrypt0Message msg = Uncompress(op.RawValue); if (msg == null) { return; } msg.SetEncryptedContent(response.Payload); SecurityContext.EntityContext recip = ctx.Recipient; if (ctx.IsGroupContext) { if (ctx.GroupId == null) { // This is not currently a valid state to be in return; } CBORObject kid = msg.FindAttribute(HeaderKeys.KeyId); if (kid == null) { // this is not currently a valid state to be in return; } recip = ctx.Recipients[kid.GetByteString()]; if (recip == null) { // M00TODO - deal with asking the user for a recipient structure at this point. return; } if (msg.FindAttribute(HeaderKeys.PartialIV) == null) { msg.AddAttribute(HeaderKeys.PartialIV, CBORObject.FromObject(ctx.Sender.PartialIV), Attributes.DO_NOT_SEND); fServerIv = false; } } else { if (msg.FindAttribute(HeaderKeys.PartialIV) == null) { msg.AddAttribute(HeaderKeys.PartialIV, CBORObject.FromObject(ctx.Sender.PartialIV), Attributes.DO_NOT_SEND); fServerIv = false; } } byte[] partialIV = msg.FindAttribute(HeaderKeys.PartialIV).GetByteString(); byte[] seqNoArray = new byte[8]; Array.Copy(partialIV, 0, seqNoArray, 8 - partialIV.Length, partialIV.Length); if (BitConverter.IsLittleEndian) { Array.Reverse(seqNoArray); } Int64 seqNo = BitConverter.ToInt64(seqNoArray, 0); if (fServerIv) { if (_replayWindow && recip.ReplayWindow.HitTest(seqNo)) { return; } } msg.AddAttribute(HeaderKeys.Algorithm, recip.Algorithm, Attributes.DO_NOT_SEND); CBORObject fullIV; if (fServerIv) { fullIV = recip.GetIV(partialIV); } else { fullIV = ctx.Sender.GetIV(partialIV); } msg.AddAttribute(HeaderKeys.IV, fullIV, Attributes.DO_NOT_SEND); // build aad CBORObject aad = CBORObject.NewArray(); aad.Add(1); // Version # aad.Add(CBORObject.NewArray()); aad[1].Add(recip.Algorithm); aad.Add(ctx.Sender.Id); aad.Add(ctx.Sender.PartialIV); aad.Add(CBORObject.FromObject(new byte[0])); // OPTIONS if (ctx.Sender.SigningAlgorithm != null) { aad[1].Add(ctx.Sender.SigningAlgorithm); if (ctx.CountersignParams != null) { aad[1].Add(ctx.CountersignParams); } if (ctx.CountersignKeyParams != null) { aad[1].Add(ctx.CountersignKeyParams); } } msg.SetExternalData(aad.EncodeToBytes()); _Log.Info(m => m($"fServerIv = {fServerIv}")); _Log.Info(m => m("ReceiveResponse: AAD = " + BitConverter.ToString(aad.EncodeToBytes()))); _Log.Info(m => m($"ReceiveResponse: IV = {BitConverter.ToString(fullIV.GetByteString())}")); _Log.Info(m => m($"ReceiveResponse: Key = {BitConverter.ToString(recip.Key)}")); if (ctx.IsGroupContext) { aad.Add(op.RawValue); int cbSignature = 64; // M00TODO Need to figure out the size of the signature from the context. byte[] rgbSignature = new byte[cbSignature]; byte[] rgbPayload = new byte[response.Payload.Length - cbSignature]; Array.Copy(response.Payload, rgbPayload, rgbPayload.Length); Array.Copy(response.Payload, rgbPayload.Length, rgbSignature, 0, cbSignature); CounterSignature1 cs1 = new CounterSignature1(rgbSignature); cs1.AddAttribute(HeaderKeys.Algorithm, ctx.Sender.SigningAlgorithm, Attributes.DO_NOT_SEND); cs1.SetObject(msg); cs1.SetKey(recip.SigningKey); byte[] aadData = aad.EncodeToBytes(); cs1.SetExternalData(aadData); msg.SetEncryptedContent(rgbPayload); try { if (!msg.Validate(cs1)) { return; } } catch (CoseException e) { // try the next possible one return; } } byte[] payload = msg.Decrypt(recip.Key); recip.ReplayWindow.SetHit(seqNo); byte[] rgb = new byte[payload.Length + _FixedHeader.Length - 1]; Array.Copy(_FixedHeader, rgb, _FixedHeader.Length); Array.Copy(payload, 1, rgb, _FixedHeader.Length, payload.Length - 1); rgb[1] = payload[0]; Codec.IMessageDecoder me = Spec.NewMessageDecoder(rgb); Response decryptedReq = me.DecodeResponse(); _Log.Info($"Inner message for OSCORE{Utils.ToString(decryptedReq)}"); response.Payload = decryptedReq.Payload; response.Code = (int)decryptedReq.StatusCode; RestoreOptions(response, decryptedReq); if (decryptedReq.HasOption(OptionType.Observe)) { if (partialIV.Length > 3) { byte[] x = new byte[3]; Array.Copy(partialIV, partialIV.Length - 3, x, 0, 3); partialIV = x; } response.AddOption(Option.Create(OptionType.Observe, partialIV)); } _Log.Info($"Outgoing message for OSCORE{Utils.ToString(response)}"); } base.ReceiveResponse(nextLayer, exchange, response); }