/// <summary> /// Computes a thumbprint of the JWK using the argument Hash Algorithm /// as per <see href="https://tools.ietf.org/html/rfc7638">RFC 7638</see>, /// JSON Web Key (JWK) Thumbprint. /// </summary> public static byte[] ComputeThumbprint(IJwsTool signer, HashAlgorithm algor) { // As per RFC 7638 Section 3, we export the JWK in a canonical form // and then produce a JSON object with no whitespace or line breaks var jwkCanon = signer.ExportJwk(true); var jwkJson = JsonConvert.SerializeObject(jwkCanon, Formatting.None); var jwkBytes = Encoding.UTF8.GetBytes(jwkJson); var jwkHash = algor.ComputeHash(jwkBytes); return(jwkHash); }
// TODO: handle "Change of TOS" error response // https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.3.4 /// <summary> /// Rotates the current Public key that is associated with this Account by the /// target ACME CA with a new Public key. If successful, updates the current /// Account key pair registered with the client. /// </summary> /// <remarks> /// https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.3.6 /// </remarks> public async Task <AccountDetails> ChangeAccountKeyAsync(IJwsTool newSigner, CancellationToken cancel = default(CancellationToken)) { var requUrl = new Uri(_http.BaseAddress, Directory.KeyChange); var message = new KeyChangeRequest { Account = Account.Kid, NewKey = newSigner.ExportJwk(), }; var innerPayload = ComputeAcmeSigned(message, requUrl.ToString(), signer: newSigner, includePublicKey: true, excludeNonce: true); var resp = await SendAcmeAsync( requUrl, method : HttpMethod.Post, message : innerPayload, cancel : cancel); Signer = newSigner; return(await DecodeAccountResponseAsync(resp, existing : Account)); }