/// <summary> /// Posts the data to the specified URI. /// </summary> /// <typeparam name="T">The type of expected result</typeparam> /// <param name="client">The client.</param> /// <param name="jwsSigner">The jwsSigner used to sign the payload.</param> /// <param name="location">The URI.</param> /// <param name="entity">The payload.</param> /// <param name="ensureSuccessStatusCode">if set to <c>true</c>, throw exception if the request failed.</param> /// <param name="retryCount">Number of retries on badNonce errors (default = 1)</param> /// <returns> /// The response from ACME server. /// </returns> /// <exception cref="Exception"> /// If the HTTP request failed and <paramref name="ensureSuccessStatusCode"/> is <c>true</c>. /// </exception> internal static async Task <AcmeHttpResponse <T> > Post <T>(this IAcmeHttpClient client, JwsSigner jwsSigner, Uri location, object entity, bool ensureSuccessStatusCode, int retryCount = 1) { var payload = jwsSigner.Sign(entity, url: location, nonce: await client.ConsumeNonce()); var response = await client.Post <T>(location, payload); while (response.Error?.Status == System.Net.HttpStatusCode.BadRequest && response.Error.Type?.CompareTo("urn:ietf:params:acme:error:badNonce") == 0 && retryCount-- > 0) { payload = jwsSigner.Sign(entity, url: location, nonce: await client.ConsumeNonce()); response = await client.Post <T>(location, payload); } if (ensureSuccessStatusCode && response.Error != null) { throw new AcmeRequestException( string.Format(Strings.ErrorFetchResource, location), response.Error); } return(response); }
/// <summary> /// Changes the registration key. /// </summary> /// <param name="account">The account.</param> /// <param name="newKey">The new registration key.</param> /// <returns>The awaitable.</returns> public async Task ChangeKey(AcmeAccount account, KeyInfo newKey) { var keyPair = new AccountKey(newKey); var body = new { account = account.Location, newKey = keyPair.JsonWebKey, }; var jws = new JwsSigner(keyPair); var payload = jws.Sign(body); var payloadWithResourceType = new { payload.Header, payload.Payload, payload.Protected, payload.Signature, Resource = ResourceTypes.KeyChange }; var uri = await this.handler.GetResourceUri(ResourceTypes.KeyChange); var result = await this.handler.Post(uri, payloadWithResourceType, key); ThrowIfError(result); this.key = keyPair; }
/// <summary> /// Revokes the certificate. /// </summary> /// <param name="certificate">The certificate in DER format.</param> /// <param name="reason">The reason for revocation.</param> /// <param name="certificatePrivateKey">The certificate's private key.</param> /// <returns> /// The awaitable. /// </returns> public async Task RevokeCertificate(byte[] certificate, RevocationReason reason, IKey certificatePrivateKey) { var endpoint = await this.GetResourceUri(d => d.RevokeCert); var body = new CertificateRevocation { Certificate = JwsConvert.ToBase64String(certificate), Reason = reason }; JwsPayload payload; if (certificatePrivateKey != null) { var jws = new JwsSigner(certificatePrivateKey); payload = jws.Sign(body, url: endpoint, nonce: await HttpClient.ConsumeNonce()); } else { payload = await Sign(body, endpoint); } await HttpClient.Post <string>(endpoint, payload, true); }
/// <summary> /// Post to the new account endpoint. /// </summary> /// <param name="context">The ACME context.</param> /// <param name="body">The payload.</param> /// <param name="ensureSuccessStatusCode">if set to <c>true</c>, throw exception if the request failed.</param> /// <returns>The ACME response.</returns> internal static async Task <AcmeHttpResponse <Account> > NewAccount( IAcmeContext context, Account body, bool ensureSuccessStatusCode) { var endpoint = await context.GetResourceUri(d => d.NewAccount); var jws = new JwsSigner(context.AccountKey); var payload = jws.Sign(body, url: endpoint, nonce: await context.HttpClient.ConsumeNonce()); return(await context.HttpClient.Post <Account>(endpoint, payload, ensureSuccessStatusCode)); }
/// <summary> /// Signs the data with account key. /// </summary> /// <param name="entity">The data to sign.</param> /// <param name="uri">The URI for the request.</param> /// <returns>The JWS payload.</returns> public async Task <JwsPayload> Sign(object entity, Uri uri) { var nonce = await HttpClient.ConsumeNonce(); var location = await Account().Location(); var jws = new JwsSigner(AccountKey); return(jws.Sign(entity, location, uri, nonce)); }
/// <summary> /// Changes the account key. /// </summary> /// <param name="key">The new account key.</param> /// <returns>The account resource.</returns> public async Task <Account> ChangeKey(IKey key) { var endpoint = await this.GetResourceUri(d => d.KeyChange); var location = await Account().Location(); var newKey = key ?? KeyFactory.NewKey(defaultKeyType); var keyChange = new { account = location, oldKey = AccountKey.JsonWebKey, }; var jws = new JwsSigner(newKey); var body = jws.Sign(keyChange, url: endpoint); var resp = await HttpClient.Post <Account>(this, endpoint, body, true); AccountKey = newKey; return(resp.Resource); }
/// <summary> /// Encodes the specified entity for ACME requests. /// </summary> /// <param name="entity">The entity.</param> /// <param name="keyPair">The key pair.</param> /// <param name="nonce">The nonce.</param> /// <returns>The encoded JSON.</returns> private static object Encode(object entity, IAccountKey keyPair, string nonce) { var encoder = new JwsSigner(keyPair.SignatureKey); return(encoder.Sign(entity, nonce)); }