1515
1616package software .amazon .awssdk .services .signin .internal ;
1717
18- import java .io .ByteArrayOutputStream ;
1918import java .io .IOException ;
2019import java .nio .charset .StandardCharsets ;
2120import java .security .InvalidKeyException ;
2827import java .util .Arrays ;
2928import java .util .Base64 ;
3029import software .amazon .awssdk .annotations .SdkInternalApi ;
31- import software .amazon .awssdk .thirdparty .jackson .core .JsonFactory ;
32- import software .amazon .awssdk .thirdparty .jackson .core .JsonGenerator ;
30+ import software .amazon .awssdk .protocols .jsoncore .JsonWriter ;
3331import software .amazon .awssdk .utils .Pair ;
3432
3533/**
3836@ SdkInternalApi
3937public final class DpopHeaderGenerator {
4038
41- public static final int ES256_SIGNATURE_BYTE_LENGTH = 64 ;
42- public static final byte DER_SEQUENCE_TAG = 0x30 ;
39+ private static final int ES256_SIGNATURE_BYTE_LENGTH = 64 ;
40+ private static final byte DER_SEQUENCE_TAG = 0x30 ;
4341
4442 private DpopHeaderGenerator () {
4543
@@ -74,12 +72,12 @@ public static String generateDPoPProofHeader(String pemContent, String endpoint,
7472 ECPublicKey publicKey = keys .right ();
7573
7674 // Build JSON strings (header, payload) with JsonGenerator
77- String headerJson = buildHeaderJson (publicKey );
78- String payloadJson = buildPayloadJson (uuid , endpoint , epochSeconds );
75+ byte [] headerJson = buildHeaderJson (publicKey );
76+ byte [] payloadJson = buildPayloadJson (uuid , endpoint , epochSeconds );
7977
8078 // Base64URL encode header + payload
81- String encodedHeader = base64UrlEncode (headerJson . getBytes ( StandardCharsets . UTF_8 ) );
82- String encodedPayload = base64UrlEncode (payloadJson . getBytes ( StandardCharsets . UTF_8 ) );
79+ String encodedHeader = base64UrlEncode (headerJson );
80+ String encodedPayload = base64UrlEncode (payloadJson );
8381 String message = encodedHeader + "." + encodedPayload ;
8482
8583 // Sign (ES256)
@@ -98,42 +96,73 @@ public static String generateDPoPProofHeader(String pemContent, String endpoint,
9896
9997 // build the JWT header which includes the public key
10098 // see: https://datatracker.ietf.org/doc/html/rfc9449#name-dpop-proof-jwt-syntax
101- private static String buildHeaderJson (ECPublicKey publicKey ) throws IOException {
99+ private static byte [] buildHeaderJson (ECPublicKey publicKey ) throws IOException {
102100 ECPoint pubPoint = publicKey .getW ();
103101 String x = base64UrlEncode (stripLeadingZero (pubPoint .getAffineX ().toByteArray ()));
104102 String y = base64UrlEncode (stripLeadingZero (pubPoint .getAffineY ().toByteArray ()));
105- ByteArrayOutputStream out = new ByteArrayOutputStream ();
106- JsonFactory factory = new JsonFactory ();
107- try (JsonGenerator gen = factory .createGenerator (out )) {
108- gen .writeStartObject ();
109- gen .writeStringField ("typ" , "dpop+jwt" );
110- gen .writeStringField ("alg" , "ES256" );
111-
112- gen .writeObjectFieldStart ("jwk" );
113- gen .writeStringField ("crv" , "P-256" );
114- gen .writeStringField ("kty" , "EC" );
115- gen .writeStringField ("x" , x );
116- gen .writeStringField ("y" , y );
117- gen .writeEndObject (); // end jwk
118- gen .writeEndObject (); // end root
103+ JsonWriter jsonWriter = null ;
104+ try {
105+ jsonWriter = JsonWriter .create ();
106+ jsonWriter .writeStartObject ();
107+ jsonWriter .writeFieldName ("typ" );
108+ jsonWriter .writeValue ("dpop+jwt" );
109+
110+ jsonWriter .writeFieldName ("alg" );
111+ jsonWriter .writeValue ("ES256" );
112+
113+ jsonWriter .writeFieldName ("jwk" );
114+ jsonWriter .writeStartObject ();
115+
116+ jsonWriter .writeFieldName ("crv" ) ;
117+ jsonWriter .writeValue ("P-256" );
118+
119+ jsonWriter .writeFieldName ("kty" );
120+ jsonWriter .writeValue ("EC" );
121+
122+ jsonWriter .writeFieldName ("x" );
123+ jsonWriter .writeValue (x );
124+
125+ jsonWriter .writeFieldName ("y" );
126+ jsonWriter .writeValue (y );
127+ jsonWriter .writeEndObject (); // end jwk
128+ jsonWriter .writeEndObject (); // end root
129+
130+ return jsonWriter .getBytes ();
131+ } finally {
132+ if (jsonWriter != null ) {
133+ jsonWriter .close ();
134+ }
119135 }
120- return out .toString ();
121136 }
122137
123138 // build claims payload
124139 // see: https://datatracker.ietf.org/doc/html/rfc9449#name-dpop-proof-jwt-syntax
125- private static String buildPayloadJson (String uuid , String endpoint , long epochSeconds ) throws IOException {
126- ByteArrayOutputStream out = new ByteArrayOutputStream ();
127- JsonFactory factory = new JsonFactory ();
128- try (JsonGenerator gen = factory .createGenerator (out )) {
129- gen .writeStartObject ();
130- gen .writeStringField ("jti" , uuid );
131- gen .writeStringField ("htm" , "POST" );
132- gen .writeStringField ("htu" , endpoint );
133- gen .writeNumberField ("iat" , epochSeconds );
134- gen .writeEndObject ();
140+ private static byte [] buildPayloadJson (String uuid , String endpoint , long epochSeconds ) throws IOException {
141+ JsonWriter jsonWriter = null ;
142+ try {
143+ jsonWriter = JsonWriter .create ();
144+ jsonWriter .writeStartObject ();
145+
146+ jsonWriter .writeFieldName ("jti" );
147+ jsonWriter .writeValue (uuid );
148+
149+ jsonWriter .writeFieldName ("htm" );
150+ jsonWriter .writeValue ("POST" );
151+
152+ jsonWriter .writeFieldName ("htu" );
153+ jsonWriter .writeValue (endpoint );
154+
155+ jsonWriter .writeFieldName ("iat" );
156+ jsonWriter .writeValue (epochSeconds );
157+
158+ jsonWriter .writeEndObject ();
159+
160+ return jsonWriter .getBytes ();
161+ } finally {
162+ if (jsonWriter != null ) {
163+ jsonWriter .close ();
164+ }
135165 }
136- return out .toString ();
137166 }
138167
139168 /**
0 commit comments