I have tried doing this for weeks but i still can't get rid off the error.
What i think is the problem is the signature because i have changed it too many times.
And i have checked on the other posts about this topic bot eather 1. I don't understand. 2. it isn't my problem.
The error comes up when i try to create a new account using pebble
This is my custom made client in C#
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Numerics;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace ACMEClient
{
class CertDirectorys
{
public string newNonce { get; private set; }
public string newAccount { get; private set; }
public string newOrder { get; private set; }
public string newAuthz { get; private set; }
public string revokeCert { get; private set; }
public string keyChange { get; private set; }
public struct metadata
{
public string termsOfService;
public string website;
public string[] caaIdentities;
public bool externalAccountRequired;
}
public metadata meta;
public CertDirectorys(string json)
{
//Paths
newNonce = JSON.GetValue(json, "newNonce");
newAccount = JSON.GetValue(json, "newAccount");
newOrder = JSON.GetValue(json, "newOrder");
newAuthz = JSON.GetValue(json, "newAuthz");
revokeCert = JSON.GetValue(json, "revokeCert");
keyChange = JSON.GetValue(json, "keyChange");
//meta
json = JSON.Navigate(json, "meta");
json = "{" + json + "}";
meta.termsOfService = JSON.GetValue(json, "termsOfService");
meta.website = JSON.GetValue(json, "website");
meta.externalAccountRequired = JSON.GetValue(json, "externalAccountRequired") == null ? false : bool.Parse(JSON.GetValue(json, "externalAccountRequired"));
int caaInd = JSON.ElementsIn(json, "caaIdentities");
if (caaInd != -1)
{
meta.caaIdentities = new string[caaInd];
for (int i = 0; i < caaInd; i++)
{
meta.caaIdentities[i] = JSON.GetValue(json, "caaIdentities[" + i + "]");
}
}
}
}
static class Program
{
static void Main(string[] args)
{
IPAddress iPAddress = Dns.GetHostAddresses(GetHostOfLink(DirPath))[0]; //----IMPORTANT
TcpClient client = new TcpClient(iPAddress.ToString(), port);
SslStream stream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(Validatecerts));
stream.AuthenticateAsClient(iPAddress.ToString(), null, SslProtocols.Tls12, false);
byte[] buffer = Encoding.UTF8.GetBytes(
"GET "+GetPathOfLink(DirPath)+" HTTP/1.1\r\n" +
"Accept-Language: en\r\n" +
"Host: "+Host+"\r\n" +
"\r\n"
);
stream.Write(buffer, 0, buffer.Length);
buffer = new byte[8192];
int size = stream.Read(buffer, 0, 8192);
string message = Encoding.UTF8.GetString(buffer, 0, size);
message = message.Substring(message.IndexOf("\r\n\r\n") + 4);
dirs = new CertDirectorys(message);
Console.WriteLine(dirs.newNonce);
string Nonce;
//Check if already have Nonce
if (!File.Exists("./nonce.txt"))
{
Stream Fstream = File.Create("./nonce.txt");
Fstream.Close();
}
using (StreamReader Fstream = new StreamReader("./nonce.txt"))
{
Nonce = Fstream.ReadLine();
}
if (Nonce == "" || Nonce == null || true)
{
Nonce = getNonce(stream);
Console.WriteLine("got new nonce: " + Nonce);
if (Nonce == null)
{
Console.WriteLine("Nonce is not valid");
Console.ReadKey();
}
}
//Generate elepric curve for keys
ECDsaCng dsa = new ECDsaCng();
dsa.HashAlgorithm = CngAlgorithm.Sha256;
dsa.KeySize = 256;
dsa.GenerateKey(ECCurve.NamedCurves.nistP256);
ECP = dsa.ExportParameters(true);
byte[] Protected = Encoding.UTF8.GetBytes(
" {\n" +
" \"alg\": \"ES256\",\n" +// ECDSA using P-256 curve and SHA-256 hash algorithm https://openid.net/specs/draft-jones-json-web-signature-04.html#Signing
" \"jwk\": {\n" +
" \"kty\": \"EC\",\n" +
" \"crv\": \"P-256\",\n" +
" \"x\": \"" + base64url(dsa.Key.Export(CngKeyBlobFormat.EccPublicBlob).split(8, 32)) + "\",\n" +
" \"y\": \"" + base64url(dsa.Key.Export(CngKeyBlobFormat.EccPublicBlob).split(8+32, 32)) + "\"\n" +
//" ,\"d\": \"" + base64url(dsa.Key.Export(CngKeyBlobFormat.EccPrivateBlob).split(8+32+32, 32)) + "\"\n" +
" },\n" +
" \"nonce\": " + Nonce + ",\n" +
" \"url\": \"" + dirs.newAccount + "\"\n" +
" }\n");
byte[] Payload = Encoding.UTF8.GetBytes(
" {\n" +
" \"termsOfServiceAgreed\": true\n" +
" }\n");
/*
*
*/
byte[] signature = Encoding.ASCII.GetBytes(base64url(Protected)+"."+base64url(Payload));// maby need convertion to ascii
//Encode with ES256
signature = dsa.SignData(signature, HashAlgorithmName.SHA256);
string json =
"{\n" +
" \"payload\": \"" + base64url(Payload) + "\",\n" +
//" \"header\": {},"+ //Just to check that the JSON isn't wrong
" \"protected\": \"" + base64url(Protected) + "\",\n" +
" \"signature\": \"" + base64url(signature) + "\"\n" +
"}";
buffer = Encoding.UTF8.GetBytes(
"POST " + GetPathOfLink(dirs.newAccount) + " HTTP/1.1\r\n" +
"Host: "+Host+"\r\n" +
//"Host: letsencrypt.org\r\n" +
"Content-Type: application/jose+json\r\n" +
"Content-Length: " + json.Length + "\r\n" +
"\r\n" + json
);
Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, buffer.Length));
stream.Write(buffer, 0, buffer.Length);
buffer = new byte[8192];
size = stream.Read(buffer, 0, 8192);
message = Encoding.UTF8.GetString(buffer, 0, size);
Console.WriteLine("---------------------------------------------\r\n"+message);
Console.ReadKey();
}
}
}
What i send
POST /sign-me-up HTTP/1.1
Host: 127.0.0.1
Content-Type: application/jose+json
Content-Length: 635
{
"payload": "ICAgewogICAgICAgInRlcm1zT2ZTZXJ2aWNlQWdyZWVkIjogdHJ1ZQogICB9Cg",
"protected": "ICAgewogICAgICAgImFsZyI6ICJFUzI1NiIsCiAgICAgICAiandrIjogewogICAgICAgICAgICJrdHkiOiAiRUMiLAogICAgICAgICAgICJjcnYiOiAiUC0yNTYiLAogICAgICAgICAgICJ4IjogIlBDZkpzbGN3YVJvd1lVVkNIaG8wLWpoNTJ0QTBpQ1lrVjVpQ05QQkZ3czQiLAogICAgICAgICAgICJ5IjogIlJCQ05Mckl5aEQ3RFZEUDR6WG5yU0VubDM1WkxvRlpmSV9paEZGb3BWdTQiCiAgICAgICB9LAogICAgICAgIm5vbmNlIjogZml4U3JTOUw0NUVEWUxCSnlVM0tkZywKICAgICAgICJ1cmwiOiAiaHR0cHM6Ly8xMjcuMC4wLjEvc2lnbi1tZS11cCIKICAgfQo",
"signature": "UjVCJiyU-I5bNB6Uoi7Ivosh4aqsoDzo-II6bq0ft5WLgK_3wDkqhFGgHdo7mP4yu7-90A5gtATvL3qnbcMzTQ"
}
The error message
HTTP/1.1 400 Bad Request
Cache-Control: public, max-age=0, no-cache
Content-Type: application/problem+json; charset=utf-8
Replay-Nonce: Ivr8UX-_qYOUDZ3gYqdS7g
Date: Sat, 08 Jan 2022 11:45:41 GMT
Content-Length: 111
{
"type": "urn:ietf:params:acme:error:malformed",
"detail": "Parse error reading JWS",
"status": 400
}