Skip to content

CloudFront Signed Url and Cookie Feature #3508

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-7051df3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"category": "AWS SDK for Java v2",
"contributor": "",
"type": "feature",
"description": "CloudFront brings feature parity for signed url and signed cookies"
}
6 changes: 6 additions & 0 deletions services/cloudfront/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,11 @@
<artifactId>protocol-core</artifactId>
<version>${awsjavasdk.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>2.17.288-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.services.cloudfront.auth;

import java.io.IOException;
import java.math.BigInteger;
import software.amazon.awssdk.annotations.SdkInternalApi;

@SdkInternalApi
public class Asn1Object {
protected final int type;
protected final int length;
protected final byte[] value;
protected final int tag;

/**
* Construct a ASN.1 TLV. The TLV could be either a
* constructed or primitive entity.
*
* <p/>The first byte in DER encoding is made of following fields,
* <pre>
*-------------------------------------------------
*|Bit 8|Bit 7|Bit 6|Bit 5|Bit 4|Bit 3|Bit 2|Bit 1|
*-------------------------------------------------
*| Class | CF | + Type |
*-------------------------------------------------
* </pre>
* <ul>
* <li>Class: Universal, Application, Context or Private
* <li>CF: Constructed flag. If 1, the field is constructed.
* <li>Type: This is actually called tag in ASN.1. It
* indicates data type (Integer, String) or a construct
* (sequence, choice, set).
* </ul>
*
* @param tag Tag or Identifier
* @param length Length of the field
* @param value Encoded octet string for the field.
*/
public Asn1Object(int tag, int length, byte[] value) {
this.tag = tag;
this.type = tag & 0x1F;
this.length = length;
this.value = value.clone();
}

public int getType() {
return type;
}

public int getLength() {
return length;
}

public byte[] getValue() {
return value.clone();
}

public boolean isConstructed() {
return (tag & DerParser.CONSTRUCTED) == DerParser.CONSTRUCTED;
}

/**
* For constructed field, return a parser for its content.
*
* @return A parser for the construct.
*/
public DerParser getParser() throws IOException {
if (!isConstructed()) {
throw new IOException("Invalid DER: can't parse primitive entity"); //$NON-NLS-1$
}

return new DerParser(value);
}

/**
* Get the value as integer
*/
public BigInteger getInteger() throws IOException {
if (type != DerParser.INTEGER) {
throw new IOException("Invalid DER: object is not integer"); //$NON-NLS-1$
}

return new BigInteger(value);
}

/**
* Get value as string. Most strings are treated
* as Latin-1.
*/
public String getString() throws IOException {

String encoding;

switch (type) {

// Not all are Latin-1 but it's the closest thing
case DerParser.NUMERIC_STRING:
case DerParser.PRINTABLE_STRING:
case DerParser.VIDEOTEX_STRING:
case DerParser.IA5_STRING:
case DerParser.GRAPHIC_STRING:
case DerParser.ISO646_STRING:
case DerParser.GENERAL_STRING:
encoding = "ISO-8859-1"; //$NON-NLS-1$
break;

case DerParser.BMP_STRING:
encoding = "UTF-16BE"; //$NON-NLS-1$
break;

case DerParser.UTF8_STRING:
encoding = "UTF-8"; //$NON-NLS-1$
break;

case DerParser.UNIVERSAL_STRING:
throw new IOException("Invalid DER: can't handle UCS-4 string"); //$NON-NLS-1$

default:
throw new IOException("Invalid DER: object is not a string"); //$NON-NLS-1$
}

return new String(value, encoding);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.services.cloudfront.auth;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import software.amazon.awssdk.annotations.SdkInternalApi;

@SdkInternalApi
public class DerParser {
// Classes
public static final int UNIVERSAL = 0x00;
public static final int APPLICATION = 0x40;
public static final int CONTEXT = 0x80;
public static final int PRIVATE = 0xC0;

// Constructed Flag
public static final int CONSTRUCTED = 0x20;

// Tag and data types
public static final int ANY = 0x00;
public static final int BOOLEAN = 0x01;
public static final int INTEGER = 0x02;
public static final int BIT_STRING = 0x03;
public static final int OCTET_STRING = 0x04;
public static final int NULL = 0x05;
public static final int OBJECT_IDENTIFIER = 0x06;
public static final int REAL = 0x09;
public static final int ENUMERATED = 0x0a;
public static final int RELATIVE_OID = 0x0d;

public static final int SEQUENCE = 0x10;
public static final int SET = 0x11;

public static final int NUMERIC_STRING = 0x12;
public static final int PRINTABLE_STRING = 0x13;
public static final int T61_STRING = 0x14;
public static final int VIDEOTEX_STRING = 0x15;
public static final int IA5_STRING = 0x16;
public static final int GRAPHIC_STRING = 0x19;
public static final int ISO646_STRING = 0x1A;
public static final int GENERAL_STRING = 0x1B;

public static final int UTF8_STRING = 0x0C;
public static final int UNIVERSAL_STRING = 0x1C;
public static final int BMP_STRING = 0x1E;

public static final int UTC_TIME = 0x17;
public static final int GENERALIZED_TIME = 0x18;

protected final InputStream in;

/**
* Create a new DER decoder from an input stream.
*
* @param in
* The DER encoded stream
*/
public DerParser(InputStream in) {
this.in = in;
}

/**
* Create a new DER decoder from a byte array.
*
* @param the encoded bytes
*/
public DerParser(byte[] bytes) {
this(new ByteArrayInputStream(bytes));
}

/**
* Read next object. If it's constructed, the value holds encoded content
* and it should be parsed by a new parser from
* {@code Asn1Object.getParser}.
*/
public Asn1Object read() throws IOException {
int tag = in.read();

if (tag == -1) {
throw new IOException("Invalid DER: stream too short, missing tag"); //$NON-NLS-1$
}

int length = getLength();

byte[] value = new byte[length];
int n = in.read(value);
if (n < length) {
throw new IOException(
"Invalid DER: stream too short, missing value"); //$NON-NLS-1$
}

return new Asn1Object(tag, length, value);

}

/**
* Decode the length of the field. Can only support length encoding up to 4
* octets.
*
* In BER/DER encoding, length can be encoded in 2 forms,
* <ul>
* <li>Short form. One octet. Bit 8 has value "0" and bits 7-1 give the
* length.
* <li>Long form. Two to 127 octets (only 4 is supported here). Bit 8 of
* first octet has value "1" and bits 7-1 give the number of additional
* length octets. Second and following octets give the length, base 256,
* most significant digit first.
* </ul>
*
* @return The length as integer
*/
private int getLength() throws IOException {

int i = in.read();
if (i == -1) {
throw new IOException("Invalid DER: length missing"); //$NON-NLS-1$
}

// A single byte short length
if ((i & ~0x7F) == 0) {
return i;
}

int num = i & 0x7F;

// We can't handle length longer than 4 bytes
if (i >= 0xFF || num > 4) {
throw new IOException("Invalid DER: length field too big (" //$NON-NLS-1$
+ i + ")"); //$NON-NLS-1$
}

byte[] bytes = new byte[num];
int n = in.read(bytes);
if (n < num) {
throw new IOException("Invalid DER: length too short"); //$NON-NLS-1$
}

return new BigInteger(1, bytes).intValue();
}
}
Loading