Пример #1
0
        /// <inheritdoc />
        public override void SendRequest(INextLayer nextLayer, Exchange exchange, Request request)
        {
            if ((request.OscoreContext != null) || (exchange.OscoreContext != null))
            {
                SecurityContext ctx = exchange.OscoreContext;
                if (request.OscoreContext != null)
                {
                    ctx = request.OscoreContext;
                    exchange.OscoreContext = ctx;
                }

                Codec.IMessageEncoder me = Spec.NewMessageEncoder();
                Request encryptedRequest = new Request(request.Method);

                if (request.Payload != null)
                {
                    encryptedRequest.Payload = request.Payload;
                }

                MoveRequestHeaders(request, encryptedRequest);

                _Log.Info(m => m("New inner response message\n{0}", encryptedRequest.ToString()));

                ctx.Sender.IncrementSequenceNumber();

                Encrypt0Message enc       = new Encrypt0Message(false);
                byte[]          msg       = me.Encode(encryptedRequest);
                int             tokenSize = msg[0] & 0xf;
                byte[]          msg2      = new byte[msg.Length - (3 + tokenSize)];
                Array.Copy(msg, 4 + tokenSize, msg2, 1, msg2.Length - 1);
                msg2[0] = msg[1];
                enc.SetContent(msg2);

                // Build AAD

                CBORObject aad = CBORObject.NewArray();
                aad.Add(CBORObject.FromObject(1)); // version
                aad.Add(CBORObject.NewArray());    // Algorithms
                aad[1].Add(CBORObject.FromObject(ctx.Sender.Algorithm));
                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);
                    }
                }
                aad.Add(CBORObject.FromObject(ctx.Sender.Id));
                aad.Add(CBORObject.FromObject(ctx.Sender.PartialIV));
                aad.Add(CBORObject.FromObject(new byte[0]));  // I options go here

                _Log.Info(m => m("SendRequest: AAD = {0}", BitConverter.ToString(aad.EncodeToBytes())));

                enc.SetExternalData(aad.EncodeToBytes());
                enc.AddAttribute(HeaderKeys.IV, ctx.Sender.GetIV(ctx.Sender.PartialIV), Attributes.DO_NOT_SEND);
                enc.AddAttribute(HeaderKeys.PartialIV, CBORObject.FromObject(ctx.Sender.PartialIV), /* Attributes.PROTECTED */ Attributes.DO_NOT_SEND);
                enc.AddAttribute(HeaderKeys.Algorithm, ctx.Sender.Algorithm, Attributes.DO_NOT_SEND);
                enc.AddAttribute(HeaderKeys.KeyId, CBORObject.FromObject(ctx.Sender.Id), /*Attributes.PROTECTED*/ Attributes.DO_NOT_SEND);
                if (ctx.GroupId != null)
                {
                    enc.AddAttribute(HeaderKeys.KidContext, CBORObject.FromObject(ctx.GroupId), Attributes.DO_NOT_SEND);
                }

                _Log.Info(m => m("SendRequest: AAD = {0}\nSendRequest: IV = {1}\nSendRequest: Key = {2}",
                                 BitConverter.ToString(aad.EncodeToBytes()),
                                 ctx.Sender.GetIV(ctx.Sender.PartialIV).GetByteString(),
                                 BitConverter.ToString(ctx.Sender.Key)));

                byte[] optionValue = BuildOscoreOption(enc);

                CounterSignature1 cs1 = null;
                if (ctx.Sender.SigningKey != null)
                {
                    cs1 = new CounterSignature1(ctx.Sender.SigningKey);
                    cs1.AddAttribute(HeaderKeys.Algorithm, ctx.Sender.SigningAlgorithm, Attributes.DO_NOT_SEND);
                    aad.Add(optionValue);
                    _Log.Info(m => m("SendRequest: AAD for Signature = {0}", BitConverter.ToString(aad.EncodeToBytes())));
                    cs1.SetExternalData(aad.EncodeToBytes());
                    cs1.SetObject(enc);
                    enc.CounterSigner1 = cs1;
                }

                enc.Encrypt(ctx.Sender.Key);

                OscoapOption o = new OscoapOption();
                o.Set(optionValue);
                request.AddOption(o);
                request.Payload = enc.GetEncryptedContent();
                if (cs1 != null)
                {
                    int    cbOrig         = request.Payload.Length;
                    byte[] rgbOrig        = request.Payload;
                    byte[] signatureBytes = cs1.EncodeToCBORObject().GetByteString();
                    Array.Resize(ref rgbOrig, cbOrig + signatureBytes.Length);
                    Array.Copy(signatureBytes, 0, rgbOrig, cbOrig, signatureBytes.Length);
                    request.Payload = rgbOrig;
                }

                request.Method = request.HasOption(OptionType.Observe) ? Method.FETCH : Method.POST;
                request.Code   = (int)request.Method;
            }
            base.SendRequest(nextLayer, exchange, request);
        }
Пример #2
0
        public override void SendResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            if (exchange.OscoreContext != null)
            {
                SecurityContext ctx = exchange.OscoreContext;

                Codec.IMessageEncoder me   = Spec.NewMessageEncoder();
                Response encryptedResponse = new Response((StatusCode)response.Code);

                if (response.Payload != null)
                {
                    encryptedResponse.Payload = response.Payload;
                }

                MoveResponseHeaders(response, encryptedResponse);

                if (_Log.IsInfoEnabled)
                {
                    _Log.Info("SendResponse: New inner response message");
                    _Log.Info(encryptedResponse.ToString());
                }

                //  Build AAD
                CBORObject aad = CBORObject.NewArray();
                aad.Add(1);
                aad.Add(CBORObject.NewArray());
                aad[1].Add(ctx.Sender.Algorithm);
                aad.Add(exchange.OscoapSenderId);
                aad.Add(exchange.OscoapSequenceNumber);
                aad.Add(CBORObject.FromObject(new byte[0])); // I 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);
                    }
                }
                if (_Log.IsInfoEnabled)
                {
                    _Log.Info("SendResponse: AAD = " + BitConverter.ToString(aad.EncodeToBytes()));
                }

                Encrypt0Message enc       = new Encrypt0Message(false);
                byte[]          msg       = me.Encode(encryptedResponse);
                int             tokenSize = msg[0] & 0xf;
                byte[]          msg2      = new byte[msg.Length - (3 + tokenSize)];
                Array.Copy(msg, 4 + tokenSize, msg2, 1, msg2.Length - 1);
                msg2[0] = msg[1];
                enc.SetContent(msg2);
                enc.SetExternalData(aad.EncodeToBytes());

                if (response.HasOption(OptionType.Observe))
                {
                    enc.AddAttribute(HeaderKeys.PartialIV, CBORObject.FromObject(ctx.Sender.PartialIV),
                                     Attributes.UNPROTECTED);
                    enc.AddAttribute(HeaderKeys.IV, ctx.Sender.GetIV(ctx.Sender.PartialIV), Attributes.DO_NOT_SEND);
                    ctx.Sender.IncrementSequenceNumber();
                    if (ctx.IsGroupContext)
                    {
                        enc.AddAttribute(HeaderKeys.KeyId, CBORObject.FromObject(ctx.Sender.Id),
                                         Attributes.UNPROTECTED);
                    }
                }
                else if (ctx.IsGroupContext)
                {
                    if (!ctx.Recipients.ContainsKey(exchange.OscoapSenderId))
                    {
                        return;
                    }
                    CBORObject iv = ctx.Recipients[exchange.OscoapSenderId].GetIV(exchange.OscoapSequenceNumber);

                    enc.AddAttribute(HeaderKeys.IV, iv, Attributes.DO_NOT_SEND);
                    enc.AddAttribute(HeaderKeys.KeyId, CBORObject.FromObject(ctx.Sender.Id),
                                     Attributes.UNPROTECTED);
                }
                else
                {
                    CBORObject iv = ctx.Recipient.GetIV(exchange.OscoapSequenceNumber);

                    enc.AddAttribute(HeaderKeys.IV, iv, Attributes.DO_NOT_SEND);
                }

                _Log.Info(m => m($"SendResponse: IV = {BitConverter.ToString(enc.FindAttribute(HeaderKeys.IV, Attributes.DO_NOT_SEND).GetByteString())}"));
                _Log.Info(m => m($"SendResponse: Key = {BitConverter.ToString(ctx.Sender.Key)}"));

                byte[] optionValue = BuildOscoreOption(enc);

                CounterSignature1 cs1 = null;
                if (ctx.IsGroupContext)
                {
                    aad.Add(optionValue);
                    cs1 = new CounterSignature1(ctx.Sender.SigningKey);
                    cs1.AddAttribute(HeaderKeys.Algorithm, ctx.Sender.SigningAlgorithm, Attributes.DO_NOT_SEND);
                    cs1.SetExternalData(aad.EncodeToBytes());
                    cs1.SetObject(enc);
                    enc.CounterSigner1 = cs1;
                }

                enc.AddAttribute(HeaderKeys.Algorithm, ctx.Sender.Algorithm, Attributes.DO_NOT_SEND);
                enc.Encrypt(ctx.Sender.Key);

                OscoapOption o = new OscoapOption(OptionType.Oscoap);
                o.Set(optionValue);
                response.AddOption(o);
                response.Code    = (int)StatusCode.Changed;
                response.Payload = enc.GetEncryptedContent();

                if (cs1 != null)
                {
                    int    cbOrig         = response.Payload.Length;
                    byte[] rgbOrig        = response.Payload;
                    byte[] signatureBytes = cs1.EncodeToCBORObject().GetByteString();
                    Array.Resize(ref rgbOrig, cbOrig + signatureBytes.Length);
                    Array.Copy(signatureBytes, 0, rgbOrig, cbOrig, signatureBytes.Length);
                    response.Payload = rgbOrig;
                }

                //  Need to be able to retrieve this again under some circumstances.

                if (encryptedResponse.HasOption(OptionType.Block2))
                {
                    Request         request = exchange.CurrentRequest;
                    Exchange.KeyUri keyUri  = new Exchange.KeyUri(request.URI, null, response.Destination);

                    //  Observe notification only send the first block, hence do not store them as ongoing
                    if (exchange.OSCOAP_ResponseBlockStatus != null &&
                        !encryptedResponse.HasOption(OptionType.Observe))
                    {
                        //  Remember ongoing blockwise GET requests
                        BlockHolder blockInfo = new BlockHolder(exchange);
                        if (Utils.Put(_ongoingExchanges, keyUri, blockInfo) == null)
                        {
                            if (_Log.IsInfoEnabled)
                            {
                                _Log.Info("Ongoing Block2 started late, storing " + keyUri + " for " + request);
                            }
                        }
                        else
                        {
                            if (_Log.IsInfoEnabled)
                            {
                                _Log.Info("Ongoing Block2 continued, storing " + keyUri + " for " + request);
                            }
                        }
                    }
                    else
                    {
                        if (_Log.IsInfoEnabled)
                        {
                            _Log.Info("Ongoing Block2 completed, cleaning up " + keyUri + " for " + request);
                        }
                        BlockHolder exc;
                        _ongoingExchanges.TryRemove(keyUri, out exc);
                    }
                }
            }

            base.SendResponse(nextLayer, exchange, response);
        }
Пример #3
0
        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);
        }
Пример #4
0
        /// <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}", 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.OscoreContext != null)
                {
                    contexts.Add(exchange.OscoreContext);
                    if (exchange.OscoreContext.GroupId != null)
                    {
                        gid = CBORObject.FromObject(exchange.OscoreContext.GroupId);
                    }
                    kid = CBORObject.FromObject(exchange.OscoapSenderId);
                }
                else
                {
                    gid = msg.FindAttribute(HeaderKeys.KidContext);
                    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));    // Version #
                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

                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 (gid != null)
                    {
                        if (recip != null)
                        {
                            if (!SecurityContext.ByteArrayComparer.AreEqual(recip.Id, kid.GetByteString()))
                            {
                                continue;
                            }
                        }
                        else
                        {
                            if (context.Recipients.ContainsKey(kid.GetByteString()))
                            {
                                recip = context.Recipients[kid.GetByteString()];
                            }
                            else
                            {
                                if (context.Locate == null)
                                {
                                    continue;
                                }
                                recip = context.Locate(context, kid.GetByteString());
                                if (recip == null)
                                {
                                    continue;
                                }
                            }
                        }
                    }

                    if (false && _replayWindow && recip.ReplayWindow.HitTest(seqNo))
                    {
                        _Log.Info(m => m("Hit test on {0} failed", seqNo));
                        responseString = "Hit test - duplicate";
                        continue;
                    }
                    else
                    {
                        _Log.Info(m => m("Hit test disabled"));
                    }

                    aad[1] = CBORObject.NewArray();
                    aad[1].Add(recip.Algorithm);
                    if (context.Sender.SigningKey != null)
                    {
                        aad[1].Add(context.Sender.SigningKey[CoseKeyKeys.Algorithm]);
                        if (context.CountersignParams != null)
                        {
                            aad[1].Add(context.CountersignParams);
                        }

                        if (context.CountersignKeyParams != null)
                        {
                            aad[1].Add(context.CountersignKeyParams);
                        }

                        int    cbSignature  = context.SignatureSize;
                        byte[] rgbSignature = new byte[cbSignature];
                        byte[] rgbPayload   = new byte[request.Payload.Length - cbSignature];

                        Array.Copy(request.Payload, rgbPayload, rgbPayload.Length);
                        Array.Copy(request.Payload, rgbPayload.Length, rgbSignature, 0, cbSignature);

                        CounterSignature1 cs1 = new CounterSignature1(rgbSignature);
                        cs1.AddAttribute(HeaderKeys.Algorithm, context.Sender.SigningAlgorithm, Attributes.DO_NOT_SEND);
                        cs1.SetObject(msg);
                        cs1.SetKey(recip.SigningKey);

                        aad.Add(op.RawValue);
                        byte[] aadData = aad.EncodeToBytes();
                        cs1.SetExternalData(aadData);
                        msg.SetEncryptedContent(rgbPayload);

                        try {
                            if (!msg.Validate(cs1))
                            {
                                continue;
                            }
                        }
                        catch (CoseException e) {
                            // try the next possible one
                            continue;
                        }
                    }

                    if (aad.Count == 6)
                    {
                        aad.Remove(aad[5]);
                    }

                    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 || request.Type == MessageType.NON)
                    {
                        response = new Response(StatusCode.BadRequest)
                        {
                            PayloadString = responseString
                        };
                        exchange.SendResponse(response);
                    }
                    return;
                }

                exchange.OscoreContext        = ctx; // So we know it on the way back.
                request.OscoreContext         = 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.OscoreContext = 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);
        }