Skip to content

Commit 4a99bf4

Browse files
committed
fix: jwk key_ops correct coding format
1 parent 13e5ae6 commit 4a99bf4

3 files changed

Lines changed: 95 additions & 16 deletions

File tree

Scripts/refresh_certs.sh

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/bin/bash
2+
3+
# Create test certificates for jose-swift
4+
ORG_NAME="Beatt83"
5+
ROOT_CN="Jose Swift Root CA"
6+
INT_CN="Jose Swift Intermediate CA"
7+
LEAF_CN="Jose Swift Leaf Certificate"
8+
EXPIRY_DAYS=3650
9+
10+
# --- The Cleanup Function ---
11+
# This runs automatically on exit, even if the script fails.
12+
cleanup() {
13+
echo -e "\n🧹 Cleaning up temporary artifacts..."
14+
rm -f *.key *.crt *.csr *.conf *.der *.txt *.raw *.srl
15+
echo "Done."
16+
}
17+
trap cleanup EXIT
18+
19+
echo "🔨 Generating Certificate Chain for $ORG_NAME..."
20+
21+
# 1. Root CA
22+
openssl ecparam -name prime256v1 -genkey -noout -out root.key
23+
openssl req -new -x509 -sha256 -key root.key -out root.crt -subj "/O=$ORG_NAME/CN=$ROOT_CN" -days $EXPIRY_DAYS 2>/dev/null
24+
25+
# 2. Intermediate CA
26+
openssl ecparam -name prime256v1 -genkey -noout -out intermediate.key
27+
openssl req -new -key intermediate.key -out intermediate.csr -subj "/O=$ORG_NAME/CN=$INT_CN" 2>/dev/null
28+
echo "basicConstraints=critical,CA:TRUE" > ca.conf
29+
openssl x509 -req -in intermediate.csr -CA root.crt -CAkey root.key -CAcreateserial -out intermediate.crt -days $EXPIRY_DAYS -extfile ca.conf 2>/dev/null
30+
31+
# 3. Leaf Certificate
32+
openssl ecparam -name prime256v1 -genkey -noout -out leaf.key
33+
openssl req -new -key leaf.key -out leaf.csr -subj "/O=$ORG_NAME/CN=$LEAF_CN" 2>/dev/null
34+
openssl x509 -req -in leaf.csr -CA intermediate.crt -CAkey intermediate.key -CAcreateserial -out leaf.crt -days $EXPIRY_DAYS 2>/dev/null
35+
36+
echo "🖋️ Signing JWT..."
37+
38+
# 4. Python packaging (Handles Base64URL and ES256 Raw Signature)
39+
python3 - <<EOF
40+
import base64, json, subprocess
41+
42+
def b64url(data):
43+
return base64.urlsafe_b64encode(data).decode('utf-8').replace('=', '')
44+
45+
def get_cert_b64(filename):
46+
with open(filename, 'r') as f:
47+
lines = f.readlines()
48+
return "".join([line.strip() for line in lines if "CERTIFICATE" not in line])
49+
50+
header = {
51+
"alg": "ES256",
52+
"typ": "JWT",
53+
"x5c": [get_cert_b64("leaf.crt"), get_cert_b64("intermediate.crt"), get_cert_b64("root.crt")]
54+
}
55+
payload = {"cool": True}
56+
57+
header_b64 = b64url(json.dumps(header).encode())
58+
payload_b64 = b64url(json.dumps(payload).encode())
59+
signing_input = f"{header_b64}.{payload_b64}".encode()
60+
61+
with open("signing_input.txt", "wb") as f: f.write(signing_input)
62+
subprocess.run("openssl dgst -sha256 -sign leaf.key -out sig.der signing_input.txt", shell=True, capture_output=True)
63+
64+
with open("sig.der", "rb") as f:
65+
der = f.read()
66+
r_len = der[3]
67+
r = der[4:4+r_len][-32:]
68+
s_len = der[4+r_len+1]
69+
s = der[4+r_len+2:4+r_len+2+s_len][-32:]
70+
signature = b64url(r + s)
71+
72+
token = f"{header_b64}.{payload_b64}.{signature}"
73+
74+
print("\n" + "="*60)
75+
print(" COPY THE BLOCK BELOW INTO YOUR SWIFT TEST")
76+
print("="*60 + "\n")
77+
78+
print('let trusted = """')
79+
with open("root.crt", "r") as f: print(f.read().strip())
80+
print('"""\n')
81+
82+
print(f'let validToken = "{token}"')
83+
EOF

Sources/JSONWebKey/JWK+Codable.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ extension JWK: Codable {
1313
enum CodingKeys: String, CodingKey {
1414
case keyType = "kty"
1515
case publicKeyUse = "use"
16-
case keyOperations = "keyOps"
16+
case keyOperations = "key_ops"
1717
case algorithm = "alg"
1818
case key = "k"
1919
case keyID = "kid"

Tests/JWTTests/X5CValidatorTests.swift

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,25 +26,21 @@ final class X5CValidatorTests: XCTestCase {
2626
let trusted =
2727
"""
2828
-----BEGIN CERTIFICATE-----
29-
MIICijCCAi+gAwIBAgIUQ+GZt69343+8jDCMflUIG4Il2MswCgYIKoZIzj0EAwIw
30-
gZkxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazERMA8GA1UEBwwITmV3
31-
IFlvcmsxDjAMBgNVBAoMBVZhcG9yMRQwEgYDVQQLDAtFbmdpbmVlcmluZzEWMBQG
32-
A1UEAwwNVmFwb3IgUm9vdCBDQTEmMCQGCSqGSIb3DQEJARYXYWRtaW5AdmFwb3Iu
33-
ZXhhbXBsZS5jb20wHhcNMjUwMTEwMDkyNzE4WhcNMzUwMTA4MDkyNzE4WjCBmTEL
34-
MAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMREwDwYDVQQHDAhOZXcgWW9y
35-
azEOMAwGA1UECgwFVmFwb3IxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRYwFAYDVQQD
36-
DA1WYXBvciBSb290IENBMSYwJAYJKoZIhvcNAQkBFhdhZG1pbkB2YXBvci5leGFt
37-
cGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABK/74uVxo9bVpbF13l3d
38-
h7txUH20FpOwW7JsNvW6yGzRrJr0JcGIUJFUml8horg/mZLQqde+LTKf4VByWlk7
39-
hBKjUzBRMB0GA1UdDgQWBBTwox5TK8yr7ZDJcieuEo6hOUJvcjAfBgNVHSMEGDAW
40-
gBTwox5TK8yr7ZDJcieuEo6hOUJvcjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49
41-
BAMCA0kAMEYCIQDDB3s+2CUl/YrXxQUbyl38GNSpXcogYfEcWXEQmQtOlgIhAJHz
42-
e7CCTDHODtGan89r2VED7tXpwGk/5EWLarTvohI3
29+
MIIBszCCAVmgAwIBAgIUXLTidX0XkEtc8XbnBkaFeF9JWGwwCgYIKoZIzj0EAwIw
30+
LzEQMA4GA1UECgwHYmVhdHQ4MzEbMBkGA1UEAwwSSm9zZSBTd2lmdCBSb290IENB
31+
MB4XDTI2MDMxNTEwMDkyOFoXDTM2MDMxMjEwMDkyOFowLzEQMA4GA1UECgwHYmVh
32+
dHQ4MzEbMBkGA1UEAwwSSm9zZSBTd2lmdCBSb290IENBMFkwEwYHKoZIzj0CAQYI
33+
KoZIzj0DAQcDQgAEgjwLVMAL24qav2t2nhe5Hwz5SHy3aggXbKZJmfGHZ8gHU7tr
34+
DlNnp2zrcCTJm9jRg9OZG1fDU8fN2+6V9NRQs6NTMFEwHQYDVR0OBBYEFK+oRfMo
35+
0Zvt2QQH6L9PssaiBjOLMB8GA1UdIwQYMBaAFK+oRfMo0Zvt2QQH6L9PssaiBjOL
36+
MA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIhAJFabGhIiKtK7pQ+
37+
1Nz1kTOFyALwW0rWvKkEsBOM6BRAAiAmjCwSbEr3Dx/czAXhaSDJgQutg0rsJR7Q
38+
4oMw9gSalg==
4339
-----END CERTIFICATE-----
4440
"""
4541

4642
let validToken = """
47-
eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlDZmpDQ0FpT2dBd0lCQWdJVUZ5b29aUm1zXC9TUzVKdllMMGRsNmhId1I1bFl3Q2dZSUtvWkl6ajBFQXdJd2dhRXhDekFKQmdOVkJBWVRBbFZUTVJFd0R3WURWUVFJREFoT1pYY2dXVzl5YXpFUk1BOEdBMVVFQnd3SVRtVjNJRmx2Y21zeERqQU1CZ05WQkFvTUJWWmhjRzl5TVJRd0VnWURWUVFMREF0RmJtZHBibVZsY21sdVp6RWVNQndHQTFVRUF3d1ZWbUZ3YjNJZ1NXNTBaWEp0WldScFlYUmxJRU5CTVNZd0pBWUpLb1pJaHZjTkFRa0JGaGRoWkcxcGJrQjJZWEJ2Y2k1bGVHRnRjR3hsTG1OdmJUQWVGdzB5TlRBeE1UQXdPVEkzTVRoYUZ3MHlOakF4TVRBd09USTNNVGhhTUlHV01Rc3dDUVlEVlFRR0V3SlZVekVSTUE4R0ExVUVDQXdJVG1WM0lGbHZjbXN4RVRBUEJnTlZCQWNNQ0U1bGR5QlpiM0pyTVE0d0RBWURWUVFLREFWV1lYQnZjakVVTUJJR0ExVUVDd3dMUlc1bmFXNWxaWEpwYm1jeEV6QVJCZ05WQkFNTUNsWmhjRzl5SUV4bFlXWXhKakFrQmdrcWhraUc5dzBCQ1FFV0YyRmtiV2x1UUhaaGNHOXlMbVY0WVcxd2JHVXVZMjl0TUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWExLUHNkMVBpczE4Wno3NzlMSTNqZTRHQ1wvR0xlZUp4eFM3VjVud0Z4U0F0U3htSlhaUGx3RDZjZEZydVhkd0p2ekpuT1ByWFdENHBZdkFNUFwvN0NTNk5DTUVBd0hRWURWUjBPQkJZRUZIXC9ja0Z0bWtKYll5aXZ5VmtvdHAyRklwTnFXTUI4R0ExVWRJd1FZTUJhQUZIUFd6am43SHhHSTJ4SHhSTkVKaHkzU1JJZVZNQW9HQ0NxR1NNNDlCQU1DQTBrQU1FWUNJUURSd1g4TTZEVEgwSmVjZGNSdDBYVTdXUlhXZkZvRUZmbGRrTFJKOVU0dlFRSWhBTHBWUFhVSVozTEx2MVVTYlk3M0pRNWNrMEk3OTJjdTVcL25hQ2VUNm84ckgiLCJNSUlDampDQ0FqU2dBd0lCQWdJVVM1Uk1IUVNQOTFFWkhaRzlHTG1LcFNcL0NxYm93Q2dZSUtvWkl6ajBFQXdJd2daa3hDekFKQmdOVkJBWVRBbFZUTVJFd0R3WURWUVFJREFoT1pYY2dXVzl5YXpFUk1BOEdBMVVFQnd3SVRtVjNJRmx2Y21zeERqQU1CZ05WQkFvTUJWWmhjRzl5TVJRd0VnWURWUVFMREF0RmJtZHBibVZsY21sdVp6RVdNQlFHQTFVRUF3d05WbUZ3YjNJZ1VtOXZkQ0JEUVRFbU1DUUdDU3FHU0liM0RRRUpBUllYWVdSdGFXNUFkbUZ3YjNJdVpYaGhiWEJzWlM1amIyMHdIaGNOTWpVd01URXdNRGt5TnpFNFdoY05NekF3TVRBNU1Ea3lOekU0V2pDQm9URUxNQWtHQTFVRUJoTUNWVk14RVRBUEJnTlZCQWdNQ0U1bGR5QlpiM0pyTVJFd0R3WURWUVFIREFoT1pYY2dXVzl5YXpFT01Bd0dBMVVFQ2d3RlZtRndiM0l4RkRBU0JnTlZCQXNNQzBWdVoybHVaV1Z5YVc1bk1SNHdIQVlEVlFRRERCVldZWEJ2Y2lCSmJuUmxjbTFsWkdsaGRHVWdRMEV4SmpBa0Jna3Foa2lHOXcwQkNRRVdGMkZrYldsdVFIWmhjRzl5TG1WNFlXMXdiR1V1WTI5dE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXR2c1JaTmFvWXhlME9FY3lTcDRQanQxWjF4NmJ2VVwvYU5PVVdjazVpZEJpWHpMZnExYXREaGpsNVpSUEFOSWozeXI3aGw0clNrZ3FramFiQXJLY250S05RTUU0d0RBWURWUjBUQkFVd0F3RUJcL3pBZEJnTlZIUTRFRmdRVWM5Yk9PZnNmRVlqYkVmRkUwUW1ITGRKRWg1VXdId1lEVlIwakJCZ3dGb0FVOEtNZVV5dk1xKzJReVhJbnJoS09vVGxDYjNJd0NnWUlLb1pJemowRUF3SURTQUF3UlFJaEFOVFFaVGxvdCtQSGk5a2NzbHl1ZHdqSXFaNTdVbms2VXdwVHJ4Wm40bXQxQWlBd3poaW5jUHNvSE5FWnIrdEFFZmtOb0crMzVGVG9jbElxV0F4aVErMnpNdz09IiwiTUlJQ2lqQ0NBaStnQXdJQkFnSVVRK0dadDY5MzQzKzhqRENNZmxVSUc0SWwyTXN3Q2dZSUtvWkl6ajBFQXdJd2daa3hDekFKQmdOVkJBWVRBbFZUTVJFd0R3WURWUVFJREFoT1pYY2dXVzl5YXpFUk1BOEdBMVVFQnd3SVRtVjNJRmx2Y21zeERqQU1CZ05WQkFvTUJWWmhjRzl5TVJRd0VnWURWUVFMREF0RmJtZHBibVZsY21sdVp6RVdNQlFHQTFVRUF3d05WbUZ3YjNJZ1VtOXZkQ0JEUVRFbU1DUUdDU3FHU0liM0RRRUpBUllYWVdSdGFXNUFkbUZ3YjNJdVpYaGhiWEJzWlM1amIyMHdIaGNOTWpVd01URXdNRGt5TnpFNFdoY05NelV3TVRBNE1Ea3lOekU0V2pDQm1URUxNQWtHQTFVRUJoTUNWVk14RVRBUEJnTlZCQWdNQ0U1bGR5QlpiM0pyTVJFd0R3WURWUVFIREFoT1pYY2dXVzl5YXpFT01Bd0dBMVVFQ2d3RlZtRndiM0l4RkRBU0JnTlZCQXNNQzBWdVoybHVaV1Z5YVc1bk1SWXdGQVlEVlFRRERBMVdZWEJ2Y2lCU2IyOTBJRU5CTVNZd0pBWUpLb1pJaHZjTkFRa0JGaGRoWkcxcGJrQjJZWEJ2Y2k1bGVHRnRjR3hsTG1OdmJUQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJLXC83NHVWeG85YlZwYkYxM2wzZGg3dHhVSDIwRnBPd1c3SnNOdlc2eUd6UnJKcjBKY0dJVUpGVW1sOGhvcmdcL21aTFFxZGUrTFRLZjRWQnlXbGs3aEJLalV6QlJNQjBHQTFVZERnUVdCQlR3b3g1VEs4eXI3WkRKY2lldUVvNmhPVUp2Y2pBZkJnTlZIU01FR0RBV2dCVHdveDVUSzh5cjdaREpjaWV1RW82aE9VSnZjakFQQmdOVkhSTUJBZjhFQlRBREFRSFwvTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDSVFEREIzcysyQ1VsXC9Zclh4UVVieWwzOEdOU3BYY29nWWZFY1dYRVFtUXRPbGdJaEFKSHplN0NDVERIT0R0R2FuODlyMlZFRDd0WHB3R2tcLzVFV0xhclR2b2hJMyJdLCJ0eXAiOiJKV1QifQ.eyJjb29sIjp0cnVlfQ.RzvCDMflF974cTCZmUkImLxYJHMTmfnCShCmvf-B38Bc4sL3POrTY-YPCDq7_ENudUKJP9WDQ-6Gn1PcjmXfaQ
43+
eyJhbGciOiAiRVMyNTYiLCAidHlwIjogIkpXVCIsICJ4NWMiOiBbIk1JSUJyakNDQVZTZ0F3SUJBZ0lVQm1xV2tJSHYzVkVyNUhPV0tnYkc5YjJUQi9Nd0NnWUlLb1pJemowRUF3SXdOekVRTUE0R0ExVUVDZ3dIWW1WaGRIUTRNekVqTUNFR0ExVUVBd3dhU205elpTQlRkMmxtZENCSmJuUmxjbTFsWkdsaGRHVWdRMEV3SGhjTk1qWXdNekUxTVRBeE1ERTFXaGNOTXpZd016RXlNVEF4TURFMVdqQXpNUkF3RGdZRFZRUUtEQWRpWldGMGREZ3pNUjh3SFFZRFZRUUREQlpLYjNObElGTjNhV1owSUVObGNuUnBabWxqWVhSbE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTJnMEwyYmNRQVN3L0YzS3pJVTF0WkJDK0ZGSlE3RUs2b2F6ZytWNC96MUh6Qzc1QmY3ZDVXRVJPWENpNmdleWp5Z0JPeXBsWHdsam9YZC9OcGtIZ0RLTkNNRUF3SFFZRFZSME9CQllFRk9PVlI2U05oN3hLZ3p6aGo0OXZFT1l0TkVDaU1COEdBMVVkSXdRWU1CYUFGRkd5V29YQ3hxMUkzRVl2Y0dxMlAxZ09GRlFwTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDSUE3dDdOUkdUSVkzNjE4dEUvK1hERXdEdGFNaEVxdTBNT2FwMFd5SW9ueTRBaUVBeHBlR09wVlM0Ym56OE41R0JMVllaSDNObGN4TG05VlViZHZqVng4SXN1az0iLCAiTUlJQnV6Q0NBV0dnQXdJQkFnSVVRVXpRS1BOSlkrbVM4Mmx1VE50cXcvUFBSZ1l3Q2dZSUtvWkl6ajBFQXdJd0x6RVFNQTRHQTFVRUNnd0hZbVZoZEhRNE16RWJNQmtHQTFVRUF3d1NTbTl6WlNCVGQybG1kQ0JTYjI5MElFTkJNQjRYRFRJMk1ETXhOVEV3TURrMU0xb1hEVE0yTURNeE1qRXdNRGsxTTFvd056RVFNQTRHQTFVRUNnd0hZbVZoZEhRNE16RWpNQ0VHQTFVRUF3d2FTbTl6WlNCVGQybG1kQ0JKYm5SbGNtMWxaR2xoZEdVZ1EwRXdXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBU2hGVmQ0aFpRc01BNXU0ZC9OVHUzamxXaFpqMWZBY2h3YXdmL1pKV1RiSG5mc1k4T0w2SkhaQll1MFNzRWtZL0NIb1hSSWFSRXJIdFk0RE5TcXZTLzRvMU13VVRBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJSUnNscUZ3c2F0U054R0wzQnF0ajlZRGhSVUtUQWZCZ05WSFNNRUdEQVdnQlN2cUVYektOR2I3ZGtFQitpL1Q3TEdvZ1l6aXpBS0JnZ3Foa2pPUFFRREFnTklBREJGQWlFQTFUZklDNi96RmUzRUMvZy9ZSjl0cjM3RlU4emJQenIrN1FvUHBGNUhCTkFDSUc1SFBqQlAzdVRCTEJUZFJtM3VuTTdyaUJzR0dwYWRSQ0JxSXlXN2VrcHUiLCAiTUlJQnN6Q0NBVm1nQXdJQkFnSVVYTFRpZFgwWGtFdGM4WGJuQmthRmVGOUpXR3d3Q2dZSUtvWkl6ajBFQXdJd0x6RVFNQTRHQTFVRUNnd0hZbVZoZEhRNE16RWJNQmtHQTFVRUF3d1NTbTl6WlNCVGQybG1kQ0JTYjI5MElFTkJNQjRYRFRJMk1ETXhOVEV3TURreU9Gb1hEVE0yTURNeE1qRXdNRGt5T0Zvd0x6RVFNQTRHQTFVRUNnd0hZbVZoZEhRNE16RWJNQmtHQTFVRUF3d1NTbTl6WlNCVGQybG1kQ0JTYjI5MElFTkJNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVnandMVk1BTDI0cWF2MnQybmhlNUh3ejVTSHkzYWdnWGJLWkptZkdIWjhnSFU3dHJEbE5ucDJ6cmNDVEptOWpSZzlPWkcxZkRVOGZOMis2VjlOUlFzNk5UTUZFd0hRWURWUjBPQkJZRUZLK29SZk1vMFp2dDJRUUg2TDlQc3NhaUJqT0xNQjhHQTFVZEl3UVlNQmFBRksrb1JmTW8wWnZ0MlFRSDZMOVBzc2FpQmpPTE1BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0NnWUlLb1pJemowRUF3SURTQUF3UlFJaEFKRmFiR2hJaUt0SzdwUSsxTnoxa1RPRnlBTHdXMHJXdktrRXNCT002QlJBQWlBbWpDd1NiRXIzRHgvY3pBWGhhU0RKZ1F1dGcwcnNKUjdRNG9NdzlnU2FsZz09Il19.eyJjb29sIjogdHJ1ZX0.JAOujM12ZgScbHF753aw9um1OgG8xSELsAa4Cc4muIdrBeSVbwEvfONBFMXHu6w2vR2Kc5UQREIHKMnlgd0Qdw
4844
"""
4945
let validator = try X5CValidator(rootCertificates: [trusted])
5046
do {

0 commit comments

Comments
 (0)