diff --git a/src/LetsEncrypt/Entities/Jws/ACMEJwsHeader.cs b/src/LetsEncrypt/Entities/Jws/ACMEJwsHeader.cs
new file mode 100644
index 0000000..e36f26a
--- /dev/null
+++ b/src/LetsEncrypt/Entities/Jws/ACMEJwsHeader.cs
@@ -0,0 +1,11 @@
+using MaksIT.Core.Security.JWS;
+using System.Text.Json.Serialization;
+
+namespace MaksIT.LetsEncrypt.Entities.Jws;
+public class ACMEJwsHeader : JwsHeader {
+ [JsonPropertyName("url")]
+ public string? Url { get; set; }
+
+ [JsonPropertyName("nonce")]
+ public string? Nonce { get; set; }
+}
diff --git a/src/LetsEncrypt/Entities/Jws/Jwk.cs b/src/LetsEncrypt/Entities/Jws/Jwk.cs
deleted file mode 100644
index 0601c59..0000000
--- a/src/LetsEncrypt/Entities/Jws/Jwk.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-// https://tools.ietf.org/html/rfc7517
-
-using System.Text.Json.Serialization;
-
-
-namespace MaksIT.LetsEncrypt.Entities.Jws;
-
-public class Jwk {
- ///
- /// "kty" (Key Type) Parameter
- ///
- /// The "kty" (key type) parameter identifies the cryptographic algorithm
- /// family used with the key, such as "RSA" or "EC".
- ///
- ///
- [JsonPropertyName("kty")]
- public string? KeyType { get; set; }
-
- ///
- /// "kid" (Key ID) Parameter
- ///
- /// The "kid" (key ID) parameter is used to match a specific key. This
- /// is used, for instance, to choose among a set of keys within a JWK Set
- /// during key rollover. The structure of the "kid" value is
- /// unspecified.
- ///
- ///
- [JsonPropertyName("kid")]
- public string? KeyId { get; set; }
-
- ///
- /// "use" (Public Key Use) Parameter
- ///
- /// The "use" (public key use) parameter identifies the intended use of
- /// the public key. The "use" parameter is employed to indicate whether
- /// a public key is used for encrypting data or verifying the signature
- /// on data.
- ///
- ///
- [JsonPropertyName("use")]
- public string? Use { get; set; }
-
- ///
- /// The the modulus value for the public RSA key. It is represented as the Base64URL encoding of value's big endian representation.
- ///
- [JsonPropertyName("n")]
- public string? Modulus { get; set; }
-
- ///
- /// The exponent value for the public RSA key. It is represented as the Base64URL encoding of value's big endian representation.
- ///
- [JsonPropertyName("e")]
- public string? Exponent { get; set; }
-
- ///
- /// The private exponent. It is represented as the Base64URL encoding of the value's big endian representation.
- ///
- [JsonPropertyName("d")]
- public string? D { get; set; }
-
- ///
- /// The first prime factor. It is represented as the Base64URL encoding of the value's big endian representation.
- ///
- [JsonPropertyName("p")]
- public string? P { get; set; }
-
- ///
- /// The second prime factor. It is represented as the Base64URL encoding of the value's big endian representation.
- ///
- [JsonPropertyName("q")]
- public string? Q { get; set; }
-
- ///
- /// The first factor Chinese Remainder Theorem exponent. It is represented as the Base64URL encoding of the value's big endian representation.
- ///
- [JsonPropertyName("dp")]
- public string? DP { get; set; }
-
- ///
- /// The second factor Chinese Remainder Theorem exponent. It is represented as the Base64URL encoding of the value's big endian representation.
- ///
- [JsonPropertyName("dq")]
- public string? DQ { get; set; }
-
- ///
- /// The first Chinese Remainder Theorem coefficient. It is represented as the Base64URL encoding of the value's big endian representation.
- ///
- [JsonPropertyName("qi")]
- public string? InverseQ { get; set; }
-
- ///
- /// The other primes information, should they exist, null or an empty list if not specified.
- ///
- [JsonPropertyName("oth")]
- public string? OthInf { get; set; }
-
- ///
- /// "alg" (Algorithm) Parameter
- ///
- /// The "alg" (algorithm) parameter identifies the algorithm intended for
- /// use with the key.
- ///
- ///
- [JsonPropertyName("alg")]
- public string? Algorithm { get; set; }
-}
diff --git a/src/LetsEncrypt/Entities/Jws/JwsMessage.cs b/src/LetsEncrypt/Entities/Jws/JwsMessage.cs
deleted file mode 100644
index ee964a5..0000000
--- a/src/LetsEncrypt/Entities/Jws/JwsMessage.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System.Text.Json.Serialization;
-
-
-namespace MaksIT.LetsEncrypt.Entities.Jws;
-
-public class JwsMessage {
-
- public string? Protected { get; set; }
-
- public string? Payload { get; set; }
-
- public string? Signature { get; set; }
-}
-
-
-public class JwsHeader {
-
- [JsonPropertyName("alg")]
- public string? Algorithm { get; set; }
-
- [JsonPropertyName("jwk")]
- public Jwk? Key { get; set; }
-
-
- [JsonPropertyName("kid")]
- public string? KeyId { get; set; }
-
- public string? Nonce { get; set; }
-
- public Uri? Url { get; set; }
-
-
- [JsonPropertyName("Host")]
- public string? Host { get; set; }
-}
diff --git a/src/LetsEncrypt/Entities/LetsEncrypt/RegistrationCache.cs b/src/LetsEncrypt/Entities/LetsEncrypt/RegistrationCache.cs
index a2ce0c5..5fa2fbd 100644
--- a/src/LetsEncrypt/Entities/LetsEncrypt/RegistrationCache.cs
+++ b/src/LetsEncrypt/Entities/LetsEncrypt/RegistrationCache.cs
@@ -2,7 +2,7 @@
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
-using MaksIT.LetsEncrypt.Entities.Jws;
+using MaksIT.Core.Security.JWK;
namespace MaksIT.LetsEncrypt.Entities;
diff --git a/src/LetsEncrypt/LetsEncrypt.csproj b/src/LetsEncrypt/LetsEncrypt.csproj
index dd0a0ec..f73bee1 100644
--- a/src/LetsEncrypt/LetsEncrypt.csproj
+++ b/src/LetsEncrypt/LetsEncrypt.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/src/LetsEncrypt/Models/Responses/Account.cs b/src/LetsEncrypt/Models/Responses/Account.cs
index b00fae4..690b7f4 100644
--- a/src/LetsEncrypt/Models/Responses/Account.cs
+++ b/src/LetsEncrypt/Models/Responses/Account.cs
@@ -1,4 +1,5 @@
-using MaksIT.LetsEncrypt.Entities.Jws;
+using MaksIT.Core.Security.JWK;
+using MaksIT.LetsEncrypt.Entities.Jws;
using MaksIT.LetsEncrypt.Models.Interfaces;
/*
diff --git a/src/LetsEncrypt/Services/JwsService.cs b/src/LetsEncrypt/Services/JwsService.cs
index ff90df7..266f014 100644
--- a/src/LetsEncrypt/Services/JwsService.cs
+++ b/src/LetsEncrypt/Services/JwsService.cs
@@ -7,14 +7,16 @@ using System.Text;
using System.Security.Cryptography;
using MaksIT.Core.Extensions;
using MaksIT.LetsEncrypt.Entities.Jws;
+using MaksIT.Core.Security.JWK;
+using MaksIT.Core.Security.JWS;
namespace MaksIT.LetsEncrypt.Services;
public interface IJwsService {
void SetKeyId(string location);
- JwsMessage Encode(JwsHeader protectedHeader);
- JwsMessage Encode(TPayload payload, JwsHeader protectedHeader);
+ JwsMessage Encode(ACMEJwsHeader protectedHeader);
+ JwsMessage Encode(TPayload payload, ACMEJwsHeader protectedHeader);
string GetKeyAuthorization(string token);
string Base64UrlEncoded(string s);
string Base64UrlEncoded(byte[] arg);
@@ -35,8 +37,8 @@ public class JwsService : IJwsService {
_jwk = new Jwk() {
KeyType = "RSA",
- Exponent = Base64UrlEncoded(exp),
- Modulus = Base64UrlEncoded(mod),
+ RsaExponent = Base64UrlEncoded(exp),
+ RsaModulus = Base64UrlEncoded(mod),
};
}
@@ -44,10 +46,10 @@ public class JwsService : IJwsService {
_jwk.KeyId = location;
}
- public JwsMessage Encode(JwsHeader protectedHeader) =>
+ public JwsMessage Encode(ACMEJwsHeader protectedHeader) =>
Encode(null, protectedHeader);
- public JwsMessage Encode(T? payload, JwsHeader protectedHeader) {
+ public JwsMessage Encode(T? payload, ACMEJwsHeader protectedHeader) {
protectedHeader.Algorithm = "RS256";
if (_jwk.KeyId != null) {
@@ -69,7 +71,6 @@ public class JwsService : IJwsService {
message.Payload = Base64UrlEncoded(payload.ToJson());
}
-
message.Signature = Base64UrlEncoded(
_rsa.SignData(Encoding.ASCII.GetBytes($"{message.Protected}.{message.Payload}"),
HashAlgorithmName.SHA256,
@@ -84,12 +85,12 @@ public class JwsService : IJwsService {
private string GetSha256Thumbprint() {
var thumbprint = new {
- e = _jwk.Exponent,
+ e = _jwk.RsaExponent,
kty = "RSA",
- n = _jwk.Modulus
+ n = _jwk.RsaModulus
};
- var json = "{\"e\":\"" + _jwk.Exponent + "\",\"kty\":\"RSA\",\"n\":\"" + _jwk.Modulus + "\"}";
+ var json = "{\"e\":\"" + _jwk.RsaExponent + "\",\"kty\":\"RSA\",\"n\":\"" + _jwk.RsaModulus + "\"}";
return Base64UrlEncoded(SHA256.HashData(Encoding.UTF8.GetBytes(json)));
}
diff --git a/src/LetsEncrypt/Services/LetsEncryptService.cs b/src/LetsEncrypt/Services/LetsEncryptService.cs
index 1e25acc..eb81592 100644
--- a/src/LetsEncrypt/Services/LetsEncryptService.cs
+++ b/src/LetsEncrypt/Services/LetsEncryptService.cs
@@ -89,8 +89,8 @@ public class LetsEncryptService : ILetsEncryptService {
await HandleNonceAsync(sessionId, challenge.Url, state);
- var pollJson = EncodeMessage(true, null, state, new JwsHeader {
- Url = challenge.Url,
+ var pollJson = EncodeMessage(true, null, state, new ACMEJwsHeader {
+ Url = challenge.Url.ToString(),
Nonce = state.Nonce
});
@@ -194,8 +194,8 @@ public class LetsEncryptService : ILetsEncryptService {
await HandleNonceAsync(sessionId, state.Directory.NewAccount, state);
- var json = EncodeMessage(false, letsEncryptOrder, state, new JwsHeader {
- Url = state.Directory.NewAccount,
+ var json = EncodeMessage(false, letsEncryptOrder, state, new ACMEJwsHeader {
+ Url = state.Directory.NewAccount.ToString(),
Nonce = state.Nonce
});
@@ -287,8 +287,8 @@ public class LetsEncryptService : ILetsEncryptService {
await HandleNonceAsync(sessionId, state.Directory.NewOrder, state);
- var json = EncodeMessage(false, letsEncryptOrder, state, new JwsHeader {
- Url = state.Directory.NewOrder,
+ var json = EncodeMessage(false, letsEncryptOrder, state, new ACMEJwsHeader {
+ Url = state.Directory.NewOrder.ToString(),
Nonce = state.Nonce
});
@@ -316,8 +316,8 @@ public class LetsEncryptService : ILetsEncryptService {
await HandleNonceAsync(sessionId, item, state);
- json = EncodeMessage(true, null, state, new JwsHeader {
- Url = item,
+ json = EncodeMessage(true, null, state, new ACMEJwsHeader {
+ Url = item.ToString(),
Nonce = state.Nonce
});
@@ -399,8 +399,8 @@ public class LetsEncryptService : ILetsEncryptService {
await HandleNonceAsync(sessionId, challenge.Url, state);
- var json = EncodeMessage(false, "{}", state, new JwsHeader {
- Url = challenge.Url,
+ var json = EncodeMessage(false, "{}", state, new ACMEJwsHeader {
+ Url = challenge.Url.ToString(),
Nonce = state.Nonce
});
@@ -440,8 +440,8 @@ public class LetsEncryptService : ILetsEncryptService {
await HandleNonceAsync(sessionId, state.Directory.NewOrder, state);
- var json = EncodeMessage(false, letsEncryptOrder, state, new JwsHeader {
- Url = state.Directory.NewOrder,
+ var json = EncodeMessage(false, letsEncryptOrder, state, new ACMEJwsHeader {
+ Url = state.Directory.NewOrder.ToString(),
Nonce = state.Nonce
});
@@ -501,8 +501,8 @@ public class LetsEncryptService : ILetsEncryptService {
await HandleNonceAsync(sessionId, state.CurrentOrder.Finalize!, state);
- var json = EncodeMessage(false, letsEncryptOrder, state, new JwsHeader {
- Url = state.CurrentOrder.Finalize,
+ var json = EncodeMessage(false, letsEncryptOrder, state, new ACMEJwsHeader {
+ Url = state.CurrentOrder.Finalize.ToString(),
Nonce = state.Nonce
});
@@ -515,8 +515,8 @@ public class LetsEncryptService : ILetsEncryptService {
await HandleNonceAsync(sessionId, state.CurrentOrder.Location!, state);
- json = EncodeMessage(true, null, state, new JwsHeader {
- Url = state.CurrentOrder.Location,
+ json = EncodeMessage(true, null, state, new ACMEJwsHeader {
+ Url = state.CurrentOrder.Location.ToString(),
Nonce = state.Nonce
});
@@ -544,8 +544,8 @@ public class LetsEncryptService : ILetsEncryptService {
await HandleNonceAsync(sessionId, certificateUrl!, state);
- var finalJson = EncodeMessage(true, null, state, new JwsHeader {
- Url = certificateUrl,
+ var finalJson = EncodeMessage(true, null, state, new ACMEJwsHeader {
+ Url = certificateUrl.ToString(),
Nonce = state.Nonce
});
@@ -617,8 +617,8 @@ public class LetsEncryptService : ILetsEncryptService {
await HandleNonceAsync(sessionId, state.Directory.RevokeCert, state);
- var jwsHeader = new JwsHeader {
- Url = state.Directory.RevokeCert,
+ var jwsHeader = new ACMEJwsHeader {
+ Url = state.Directory.RevokeCert.ToString(),
Nonce = state.Nonce
};
@@ -691,7 +691,7 @@ public class LetsEncryptService : ILetsEncryptService {
}
}
- private string EncodeMessage(bool isPostAsGet, object? requestModel, State state, JwsHeader jwsHeader) {
+ private string EncodeMessage(bool isPostAsGet, object? requestModel, State state, ACMEJwsHeader jwsHeader) {
return isPostAsGet
? state.JwsService!.Encode(jwsHeader).ToJson()
: state.JwsService!.Encode(requestModel, jwsHeader).ToJson();
diff --git a/src/MaksIT.Webapi/Dockerfile b/src/MaksIT.Webapi/Dockerfile
index 8537442..0299e2c 100644
--- a/src/MaksIT.Webapi/Dockerfile
+++ b/src/MaksIT.Webapi/Dockerfile
@@ -8,7 +8,7 @@ EXPOSE 5000
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
-COPY ["Models/Models.csproj", "Models/"]
+COPY ["MaksIT.Models/MaksIT.Models.csproj", "MaksIT.Models/"]
COPY ["LetsEncrypt/LetsEncrypt.csproj", "LetsEncrypt/"]
COPY ["MaksIT.Webapi/MaksIT.Webapi.csproj", "MaksIT.Webapi/"]
RUN dotnet restore "./MaksIT.Webapi/MaksIT.Webapi.csproj"
diff --git a/src/Models/MaksIT.Models.csproj b/src/Models/MaksIT.Models.csproj
index ff6c3e0..36b534b 100644
--- a/src/Models/MaksIT.Models.csproj
+++ b/src/Models/MaksIT.Models.csproj
@@ -11,7 +11,7 @@
-
+