예제 #1
0
        private Byte[] signed_request(String url, PmlDictionary payload)
        {
            RegisterKey();
            String payload64 = urlbase64(Encoding.UTF8.GetBytes(PmlJsonWriter.EncodeMessage(payload)));

            using (WebClient wc = new WebClient()) {
                String nonce = Interlocked.Exchange(ref replay_nonce, null);
                if (nonce == null)
                {
                    wc.DownloadString(acme_url + "/directory");
                    nonce = wc.ResponseHeaders["Replay-Nonce"];
                }
                RSAParameters account_key_params = account_key.ExportParameters(false);
                String        pubExponent64      = urlbase64(account_key_params.Exponent);
                String        pubMod64           = urlbase64(account_key_params.Modulus);
                PmlDictionary header             = new PmlDictionary()
                {
                    { "alg", "RS256" }, { "jwk", new PmlDictionary()
                                          {
                                              { "e", pubExponent64 }, { "kty", "RSA" }, { "n", pubMod64 }
                                          } }
                };
                PmlDictionary prot = new PmlDictionary()
                {
                    { "alg", "RS256" }, { "jwk", new PmlDictionary()
                                          {
                                              { "e", pubExponent64 }, { "kty", "RSA" }, { "n", pubMod64 }
                                          } }, { "nonce", nonce }
                };
                String protected64 = urlbase64(Encoding.ASCII.GetBytes(PmlJsonWriter.EncodeMessage(prot)));
                String signed64;
                using (SHA256 sha = SHA256.Create()) signed64 = urlbase64(account_key.SignData(Encoding.ASCII.GetBytes(protected64 + "." + payload64), sha));
                PmlDictionary data = new PmlDictionary()
                {
                    { "header", header }, { "protected", protected64 }, { "payload", payload64 }, { "signature", signed64 }
                };
                Byte[] ret = wc.UploadData(url, Encoding.UTF8.GetBytes(PmlJsonWriter.EncodeMessage(data)));
                if (!String.IsNullOrEmpty(wc.ResponseHeaders["Replay-Nonce"]))
                {
                    replay_nonce = wc.ResponseHeaders["Replay-Nonce"];
                }
                return(ret);
            }
        }
예제 #2
0
        public void AuthorizeDomains(String[] domains, CreateHTTPChallengeCallback challenge_callback)
        {
            RegisterKey();
            RSAParameters account_key_params = account_key.ExportParameters(false);
            String        thumbprint;

            using (SHA256 sha = SHA256.Create()) thumbprint = urlbase64(sha.ComputeHash(Encoding.UTF8.GetBytes(PmlJsonWriter.EncodeMessage(new PmlDictionary()
                {
                    { "e", urlbase64(account_key_params.Exponent) },
                    { "kty", "RSA" },
                    { "n", urlbase64(account_key_params.Modulus) }
                }))));
            foreach (String altname in domains)
            {
                Byte[] response_string = signed_request(acme_url + "/acme/new-authz", new PmlDictionary()
                {
                    { "resource", "new-authz" }, { "identifier", new PmlDictionary()
                                                   {
                                                       { "type", "dns" }, { "value", altname }
                                                   } }
                });
                PmlDictionary response   = (PmlDictionary)PmlJsonReader.DecodeMessage(response_string);
                PmlCollection challenges = (PmlCollection)response["challenges"];
                PmlDictionary challenge  = null;
                foreach (PmlDictionary item in challenges)
                {
                    if ((String)item["type"] == "http-01")
                    {
                        challenge = item;
                    }
                }
                String challenge_token = (String)challenge["token"];
                String challenge_uri   = (String)challenge["uri"];
                String keyauth         = challenge_token + "." + thumbprint;
                challenge_callback("/.well-known/acme-challenge/" + challenge_token, keyauth);
                try {
                    response_string = signed_request(challenge_uri, new PmlDictionary()
                    {
                        { "resource", "challenge" }, { "keyAuthorization", keyauth }
                    });
                    response = (PmlDictionary)PmlJsonReader.DecodeMessage(response_string);
                    while ((String)response["status"] == "pending")
                    {
                        Thread.Sleep(1000);
                        using (WebClient wc = new WebClient()) response_string = wc.DownloadData(challenge_uri);
                        response = (PmlDictionary)PmlJsonReader.DecodeMessage(response_string);
                    }
                } finally {
                    challenge_callback("/.well-known/acme-challenge/" + challenge_token, null);
                }
                if ((String)response["status"] != "valid")
                {
                    throw new InvalidOperationException("Challenge rejected for domain " + altname + " (" + response["status"] + ")");
                }
            }
        }