Пример #1
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);
        }
Пример #2
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);
        }