public void Process(Request request, Response response) { // Is this processable? if (response.StatusCode != StatusCode.Unauthorized || response.ContentFormat != 65008) { return; } try { // Init from the response data Oauth.AsInfo info = new Oauth.AsInfo(response.Payload); // Missage this as needed. string aSServer = info.ASServer; // Need to build one from scratch if (!authServers.ContainsKey(info.ASServer)) { Console.WriteLine($"No security association is setup for {info.ASServer}"); return; } AuthServerInfo asi = authServers[info.ASServer]; if (asi.ClientLink == null) { asi.ClientLink = new CoapClient(new Uri(info.ASServer)); if (asi.UseDTLS) { asi.ClientLink.EndPoint = new DTLSClientEndPoint(asi.TlsKey); asi.ClientLink.EndPoint.Start(); } } // M00BUG - need to make sure that this will pickup a port number if given. string audience = $"{request.URI.Scheme}://{request.URI.Authority}"; Oauth.Request myRequest = new Oauth.Request("client_credentials") { Audience = audience, Scope = CBORObject.FromObject(request.UriPath) }; myRequest.Profile = Profile; byte[] payload = myRequest.EncodeToBytes(); asi.ClientLink.Timeout = 2 * 60 * 1000; Response asResponse = asi.ClientLink.Post(payload, MediaType.ApplicationCbor); if (asResponse == null) { asi.ClientLink.EndPoint.Stop(); asi.ClientLink = null; Console.WriteLine($"Timed out requesting token from {info.ASServer}"); return; } if (asResponse.StatusCode != StatusCode.Created) { // We had an error condition appear if (asResponse.Payload != null) { CBORObject obj = CBORObject.DecodeFromBytes(asResponse.Payload); int error = obj["error"].AsInt32(); string errorText = ""; if (obj.ContainsKey("error_description")) { errorText = obj["error_description"].AsString(); } Console.WriteLine( $"Recieved an error {asResponse.StatusCode} with error no = {error} and description '{errorText}'"); } else { Console.WriteLine($"Received and error {asResponse.StatusCode} from the AS but no text"); } return; } Oauth.Response myResponse = new Oauth.Response(asResponse.Payload); // default profile for client - #if false if (Profile != null && myResponse.Profile != Profile) { Console.WriteLine("AS Server returned an unexpected profile {0}", myResponse.Profile); return; } #endif myResponse.Profile = Oauth.ProfileIds.Coap_Dtls; // Post token to resource server CoapClient client = new CoapClient(); client.Uri = new Uri($"coap://{request.URI.Authority}/authz-info"); client.Timeout = 10000; // 1 second Response tknResponse = client.Post(myResponse.Token, MediaType.ApplicationCbor); if (tknResponse == null) { Console.WriteLine("Post of token failed w/ no response"); return; } if (tknResponse.StatusCode != StatusCode.Created) { Console.WriteLine($"Post of token failed with error {tknResponse.StatusCode}"); return; } Confirmation cnf = myResponse.Confirmation; Request newRequest = new Request(request.Method); newRequest.Payload = request.Payload; newRequest.SetOptions(request.GetOptions()); DTLSClientEndPoint endPoint = null; switch (myResponse.Profile) { case Oauth.ProfileIds.Coap_Dtls: { OneKey key = cnf.Key; endPoint = new DTLSClientEndPoint(cnf.Key); endPoint.Start(); newRequest.EndPoint = endPoint; newRequest.URI = new Uri($"coaps://{request.URI.Authority}/{request.URI.AbsolutePath}"); } break; case Oauth.ProfileIds.Coap_Oscore: { OneKey oneKey = cnf.Key; byte[] salt = null; if (oneKey.ContainsName("slt")) { salt = oneKey[CBORObject.FromObject("slt")].GetByteString(); } CBORObject alg = null; if (oneKey.ContainsName(CoseKeyKeys.Algorithm)) { alg = oneKey[CoseKeyKeys.Algorithm]; } CBORObject kdf = null; if (oneKey.ContainsName(CBORObject.FromObject("kdf"))) { kdf = oneKey[CBORObject.FromObject("kdf")]; } SecurityContext oscoapContext = SecurityContext.DeriveContext( oneKey[CoseKeyParameterKeys.Octet_k].GetByteString(), oneKey[CBORObject.FromObject("sid")].GetByteString(), oneKey[CBORObject.FromObject("rid")].GetByteString(), salt, alg, kdf); newRequest.OscoapContext = oscoapContext; } break; default: Console.WriteLine("Cannot rewrite as we don't recognize the profile"); return; } newRequest.Respond += delegate(Object sender, ResponseEventArgs e) { Response responseN = e.Response; if (responseN == null) { Console.WriteLine("Request timeout"); } else { Console.WriteLine(Utils.ToString(responseN)); Console.WriteLine("Time (ms): " + responseN.RTT); } if (endPoint != null) { endPoint.Stop(); } }; newRequest.Send(); } catch (Exception e) { Console.WriteLine("Error processing AceAuthz - " + e.ToString()); } }
public void Process(Request request, Response response) { // Is this processable? if (response.StatusCode != StatusCode.Unauthorized /* || * !(response.ContentFormat == 65008 || response.ContentFormat == MediaType.ApplicationCbor)*/) { return; } try { // Init from the response data Oauth.AsInfo info = new Oauth.AsInfo(response.Payload); // Massage this as needed. string aSServer = info.ASServer; // Need to build one from scratch if (!authServers.ContainsKey(info.ASServer)) { Console.WriteLine($"No security association is setup for {info.ASServer}"); return; } AuthServerInfo asi = authServers[info.ASServer]; if (asi.ClientLink == null) { asi.ClientLink = new CoapClient(new Uri(info.ASServer)); if (asi.UseDTLS) { asi.ClientLink.EndPoint = new DTLSClientEndPoint(asi.TlsKey); asi.ClientLink.EndPoint.Start(); } else { if (asi.ClientLink.Uri.Scheme == "coaps") { asi.ClientLink.Uri = new Uri($"coap://{asi.ClientLink.Uri.Authority}/{asi.ClientLink.UriPath}"); } asi.ClientLink.OscoreContext = asi.OscoreKey; } } // M00BUG - need to make sure that this will pickup a port number if given. string audience = $"{request.URI.Scheme}://{request.URI.Authority}"; if (UseAudience != null) { audience = UseAudience; } Oauth.Request myRequest = new Oauth.Request("client_credentials") { Audience = audience, Scope = (UseScopeValue == null) ? CBORObject.FromObject(request.UriPath) : UseScopeValue }; if (ClientKey != null) { myRequest.Cnf = new Confirmation(); switch (ClientKeyType) { case 1: // kid myRequest.Cnf.Kid = ClientKey.PrivateKey[CoseKeyKeys.KeyIdentifier].GetByteString(); break; case 2: // key myRequest.Cnf.Key = ClientKey.PrivateKey; break; } } Response asResponse; if (asi.UseJSON) { string jsonPayload = myRequest.EncodeToString(); asi.ClientLink.Timeout = 2 * 60 * 1000; asResponse = asi.ClientLink.Post(jsonPayload, MediaType.ApplicationJson); } else { byte[] payload = myRequest.EncodeToBytes(); asi.ClientLink.Timeout = 2 * 60 * 1000; asResponse = asi.ClientLink.Post(payload, MediaType.ApplicationCbor); } if (asResponse == null) { asi.ClientLink.EndPoint.Stop(); asi.ClientLink = null; Console.WriteLine($"Timed out requesting token from {info.ASServer}"); return; } if (asResponse.StatusCode != StatusCode.Created) { // We had an error condition appear if (asResponse.Payload != null) { CBORObject obj = CBORObject.DecodeFromBytes(asResponse.Payload); int error = obj[/*"error"*/ CBORObject.FromObject(15)].AsInt32(); string errorText = ""; if (obj.ContainsKey(/*"error_description")*/ CBORObject.FromObject(16))) { errorText = obj[CBORObject.FromObject(16)].AsString(); } Console.WriteLine( $"Received an error {asResponse.StatusCode} with error no = {error} and description '{errorText}'"); } else { Console.WriteLine($"Received and error {asResponse.StatusCode} from the AS but no text"); } return; } Oauth.Response myResponse = Oauth.Response.FromCBOR(asResponse.Payload); // default profile for client - #if false if (Profile != null && myResponse.Profile != Profile) { Console.WriteLine("AS Server returned an unexpected profile {0}", myResponse.Profile); return; } #endif if (!myResponse.ContainsKey(Oauth.Oauth_Parameter.Profile)) { myResponse.Profile = Oauth.ProfileIds.Coap_Dtls; } // Post token to resource server byte[][] OscoreSalts = null; if (!SendTokenAsPsk) { CoapClient client = new CoapClient(); client.Uri = new Uri($"coap://{request.URI.Authority}/authz-info"); client.Timeout = 10000; // 1 second Response tknResponse = null; if (myResponse.Profile == Oauth.ProfileIds.Coap_Oscore) { byte[] mySalt = new byte[] { 32, 33, 34, 35, 36, 37, 38 }; CBORObject post = CBORObject.NewMap(); post.Add((CBORObject)Oauth.Oauth_Parameter.Access_Token, myResponse.Token); post.Add((CBORObject)Oauth.Oauth_Parameter.CNonce, mySalt); tknResponse = client.Post(post.EncodeToBytes(), MediaType.ApplicationAceCbor); OscoreSalts = new byte[][] { mySalt, null }; } else { tknResponse = client.Post(myResponse.Token, MediaType.ApplicationOctetStream); } if (tknResponse == null) { Console.WriteLine("Post of token failed w/ no response"); return; } if (tknResponse.StatusCode != StatusCode.Created) { Console.WriteLine($"Post of token failed with error {tknResponse.StatusCode}"); return; } if (tknResponse.ContentType == MediaType.ApplicationAceCbor) { CBORObject post = CBORObject.DecodeFromBytes(tknResponse.Payload); if (post.ContainsKey((CBORObject)Oauth.Oauth_Parameter.Client_id)) { // Retrieve } if (post.ContainsKey((CBORObject)Oauth.Oauth_Parameter.CNonce)) { if (OscoreSalts == null) { throw new Exception("Internal Error - salts"); } OscoreSalts[1] = post[(CBORObject)Oauth.Oauth_Parameter.CNonce].GetByteString(); } } } Confirmation cnf = myResponse.Confirmation; if (cnf == null) { if (ClientKey == null) { Console.WriteLine("Returned a token but I don't know what key I should be using"); return; } cnf = new Confirmation(ClientKey.PrivateKey); } if (cnf.Kid != null) { Console.WriteLine("Missing code - how do we map a kid to a real key?"); return; } Request newRequest = new Request(request.Method); newRequest.Payload = request.Payload; newRequest.SetOptions(request.GetOptions()); DTLSClientEndPoint endPoint = null; switch (myResponse.Profile) { case Oauth.ProfileIds.Coap_Dtls: { OneKey key = cnf.Key; LastKeyFound = cnf.Key; if (SendTokenAsPsk) { cnf.Key.AsCBOR().Set(CoseKeyKeys.KeyIdentifier, CBORObject.FromObject(myResponse.Token)); } endPoint = new DTLSClientEndPoint(cnf.Key); endPoint.Start(); if (myResponse.RsConfirmation != null) { ResourceInfo rsInfo = new ResourceInfo(myResponse.RsConfirmation.Key); endPoint.TlsEventHandler += rsInfo.CheckRPK; } newRequest.EndPoint = endPoint; newRequest.URI = new Uri($"coaps://{request.URI.Authority}/{request.URI.AbsolutePath}"); } break; case Oauth.ProfileIds.Coap_Oscore: { CBORObject oscoreContext = cnf.AsCBOR[CBORObject.FromObject(Confirmation.ConfirmationIds.COSE_OSCORE)]; byte[] salt = new byte[0]; if (oscoreContext.ContainsKey(CBORObject.FromObject(6))) { salt = oscoreContext[CBORObject.FromObject(CBORObject.FromObject(6))].GetByteString(); } CBORObject alg = null; if (oscoreContext.ContainsKey(CBORObject.FromObject(5))) { alg = oscoreContext[CBORObject.FromObject(5)]; } CBORObject kdf = null; if (oscoreContext.ContainsKey(CBORObject.FromObject(4))) { kdf = oscoreContext[CBORObject.FromObject(4)]; } byte[] keyContext = null; if (oscoreContext.ContainsKey(CBORObject.FromObject(7))) { keyContext = oscoreContext[CBORObject.FromObject(7)].GetByteString(); } if (OscoreSalts == null) { throw new Exception("Internal Error"); } byte[] newSalt = new byte[salt.Length + OscoreSalts[0].Length + OscoreSalts[1].Length]; Array.Copy(salt, newSalt, salt.Length); Array.Copy(OscoreSalts[0], 0, newSalt, salt.Length, OscoreSalts[0].Length); Array.Copy(OscoreSalts[1], 0, newSalt, salt.Length + OscoreSalts[0].Length, OscoreSalts[1].Length); SecurityContext oscoapContext = SecurityContext.DeriveContext( oscoreContext[CBORObject.FromObject(1)].GetByteString(), keyContext, oscoreContext[CBORObject.FromObject(2)].GetByteString(), oscoreContext[CBORObject.FromObject(3)].GetByteString(), newSalt, alg, kdf); newRequest.OscoreContext = oscoapContext; newRequest.URI = new Uri($"coap://{request.URI.Authority}/{request.URI.AbsolutePath}"); } break; default: Console.WriteLine("Cannot rewrite as we don't recognize the profile"); return; } newRequest.Respond += delegate(object sender, ResponseEventArgs e) { Response responseN = e.Response; if (responseN == null) { Console.WriteLine("Request timeout"); } else { Console.WriteLine(Utils.ToString(responseN)); Console.WriteLine("Time (ms): " + responseN.RTT); } if (endPoint != null) { endPoint.Stop(); } }; newRequest.Send(); } catch (Exception e) { Console.WriteLine("Error processing AceAuthz - " + e.ToString()); } }