Skip to content

Commit

Permalink
Support FIPS endpoints for AWS KMS (#245)
Browse files Browse the repository at this point in the history
  • Loading branch information
sbstjn authored and ebourg committed Oct 23, 2024
1 parent cb3ae0a commit 49d9f10
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 4 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ See https://ebourg.github.io/jsign for more information.
* The value of the `storetype` parameter is now case insensitive
* The Azure Key Vault account no longer needs the permission to list the keys when signing with jarsigner
* The DigiCert ONE host can now be specified with the `keystore` parameter
* The `AWS_USE_FIPS_ENDPOINT` environment variable is now supported to use the AWS KMS FIPS endpoints (contributed by Sebastian Müller)
* On Windows the YubiKey library path is automatically added to the PATH of the command line tool
* Signing more than one file with the `YUBIKEY` storetype no longer triggers a `CKR_USER_NOT_LOGGED_IN` error
* MS Cabinet files with a pre-allocated reserve are now supported
Expand Down
7 changes: 5 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,9 @@ <h4 id="example-piv">Signing with a PIV card</h4>
<h4 id="example-awskms">Signing with AWS Key Management Service</h4>

<p><a href="https://aws.amazon.com/kms/">AWS Key Management Service</a> (KMS) stores only the private key,
the certificate must be provided separately. The <code>keystore</code> parameter references the AWS region.</p>
the certificate must be provided separately. The <code>keystore</code> parameter references the AWS region.
Setting the <code>AWS_USE_FIPS_ENDPOINT</code> environment variable to <code>true</code> will ensure the FIPS
endpoint is used.</p>

<p>The AWS access key, secret key, and optionally the session token, are concatenated
and used as the <code>storepass</code> parameter; if the latter is not provided, Jsign attempts to fetch the credentials
Expand Down Expand Up @@ -1044,7 +1046,8 @@ <h3 id="credits">Credits</h3>
MSI signing was possible thanks to the work done by the <a href="https://github.com/mtrojnar/osslsigncode">osslsigncode</a> and <a href="https://poi.apache.org/">Apache POI</a> projects.</p>

<p>Jsign includes contributions from Emmanuel Bourg, Florent Daigniere, Michael Szediwy, Michael Peterson, Markus Kilås,
Erwin Tratar, Björn Kautler, Joseph Lee, Maria Merkel, Vincent Malmedy, Sebastian Stamm and Eatay Mizrachi.</p>
Erwin Tratar, Björn Kautler, Joseph Lee, Maria Merkel, Vincent Malmedy, Sebastian Müller, Sebastian Stamm
and Eatay Mizrachi.</p>

<h3 id="contacts">Contact</h3>

Expand Down
19 changes: 17 additions & 2 deletions jsign-crypto/src/main/java/net/jsign/jca/AmazonSigningService.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public class AmazonSigningService implements SigningService {
* @since 6.0
*/
public AmazonSigningService(String region, Supplier<AmazonCredentials> credentials, Function<String, Certificate[]> certificateStore) {
this(credentials, certificateStore, "https://kms." + region + ".amazonaws.com");
this(credentials, certificateStore, getEndpointUrl(region));
}

/**
Expand Down Expand Up @@ -123,6 +123,17 @@ public AmazonSigningService(String region, String credentials, Function<String,
this(region, AmazonCredentials.parse(credentials), certificateStore);
}

/**
* Returns the endpoint URL for the given AWS region.
*
* @param region the AWS region
* @return the endpoint URL
*/
static String getEndpointUrl(String region) {
String domain = "true".equalsIgnoreCase(getenv("AWS_USE_FIPS_ENDPOINT")) ? "kms-fips" : "kms";
return "https://" + domain + "." + region + ".amazonaws.com";
}

@Override
public String getName() {
return "AWS";
Expand Down Expand Up @@ -259,7 +270,7 @@ void sign(HttpURLConnection conn, AmazonCredentials credentials, byte[] content,
String host = endpoint.getHost();
Matcher matcher = hostnamePattern.matcher(host);
String regionName = matcher.matches() ? matcher.group(2) : "us-east-1";
String serviceName = matcher.matches() ? matcher.group(1) : "kms";
String serviceName = matcher.matches() ? matcher.group(1).replace("-fips", "") : "kms";

String credentialScope = dateFormat.format(date) + "/" + regionName + "/" + serviceName + "/" + "aws4_request";

Expand Down Expand Up @@ -331,4 +342,8 @@ private String sha256(byte[] data) {
digest.update(data);
return Hex.toHexString(digest.digest()).toLowerCase();
}

static String getenv(String name) {
return System.getenv(name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockedStatic;

import static net.jadler.Jadler.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

public class AmazonSigningServiceTest {

Expand Down Expand Up @@ -330,4 +332,19 @@ private String getAuthorizationHeaderValue(HttpURLConnection conn) throws Except
sun.net.www.MessageHeader headers = (sun.net.www.MessageHeader) requests.get(delegate.get(conn));
return headers.findValue("Authorization");
}

@Test
public void testGetEndpointUrl() {
// Test default endpoint
try (MockedStatic<?> mock = mockStatic(AmazonSigningService.class, CALLS_REAL_METHODS)) {
when(AmazonSigningService.getenv("AWS_USE_FIPS_ENDPOINT")).thenReturn("false");
assertEquals("https://kms.us-west-2.amazonaws.com", AmazonSigningService.getEndpointUrl("us-west-2"));
}

// Test FIPS endpoint
try (MockedStatic<?> mock = mockStatic(AmazonSigningService.class, CALLS_REAL_METHODS)) {
when(AmazonSigningService.getenv("AWS_USE_FIPS_ENDPOINT")).thenReturn("true");
assertEquals("https://kms-fips.us-west-2.amazonaws.com", AmazonSigningService.getEndpointUrl("us-west-2"));
}
}
}

0 comments on commit 49d9f10

Please sign in to comment.