mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
Merge
Reviewed-by: alanb, dfuchs
This commit is contained in:
commit
cf5bb12731
79 changed files with 3346 additions and 911 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -56,6 +56,7 @@ final class DHPrivateKey implements PrivateKey,
|
|||
private final BigInteger x;
|
||||
|
||||
// the key bytes, without the algorithm information
|
||||
// cannot be final as it's re-assigned for deserialization
|
||||
private byte[] key;
|
||||
|
||||
// the encoded key
|
||||
|
@ -70,6 +71,131 @@ final class DHPrivateKey implements PrivateKey,
|
|||
// the private-value length (optional)
|
||||
private final int l;
|
||||
|
||||
private static class DHComponents {
|
||||
final BigInteger x;
|
||||
final BigInteger p;
|
||||
final BigInteger g;
|
||||
final int l;
|
||||
final byte[] key;
|
||||
|
||||
DHComponents(BigInteger x, BigInteger p, BigInteger g, int l,
|
||||
byte[] key) {
|
||||
this.x = x;
|
||||
this.p = p;
|
||||
this.g = g;
|
||||
this.l = l;
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
|
||||
// parses the specified encoding into a DHComponents object
|
||||
private static DHComponents decode(byte[] encodedKey)
|
||||
throws IOException {
|
||||
DerValue val = null;
|
||||
|
||||
try {
|
||||
val = new DerValue(encodedKey);
|
||||
if (val.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("Key not a SEQUENCE");
|
||||
}
|
||||
|
||||
// version
|
||||
BigInteger parsedVersion = val.data.getBigInteger();
|
||||
if (!parsedVersion.equals(PKCS8_VERSION)) {
|
||||
throw new IOException("version mismatch: (supported: " +
|
||||
PKCS8_VERSION + ", parsed: " + parsedVersion);
|
||||
}
|
||||
|
||||
// privateKeyAlgorithm
|
||||
DerValue algid = val.data.getDerValue();
|
||||
if (algid.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("AlgId is not a SEQUENCE");
|
||||
}
|
||||
DerInputStream derInStream = algid.toDerInputStream();
|
||||
ObjectIdentifier oid = derInStream.getOID();
|
||||
if (oid == null) {
|
||||
throw new IOException("Null OID");
|
||||
}
|
||||
if (derInStream.available() == 0) {
|
||||
throw new IOException("Parameters missing");
|
||||
}
|
||||
// parse the parameters
|
||||
DerValue params = derInStream.getDerValue();
|
||||
if (params.tag == DerValue.tag_Null) {
|
||||
throw new IOException("Null parameters");
|
||||
}
|
||||
if (params.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("Parameters not a SEQUENCE");
|
||||
}
|
||||
params.data.reset();
|
||||
BigInteger p = params.data.getBigInteger();
|
||||
BigInteger g = params.data.getBigInteger();
|
||||
// Private-value length is OPTIONAL
|
||||
int l = (params.data.available() != 0 ?
|
||||
params.data.getInteger() : 0);
|
||||
// should have no trailing data
|
||||
if (params.data.available() != 0) {
|
||||
throw new IOException("Extra parameter data");
|
||||
}
|
||||
|
||||
// privateKey
|
||||
byte[] key = val.data.getOctetString();
|
||||
DerInputStream in = new DerInputStream(key);
|
||||
BigInteger x = in.getBigInteger();
|
||||
|
||||
// should have no trailing data
|
||||
if (val.data.available() != 0) {
|
||||
throw new IOException("Excess trailing data");
|
||||
}
|
||||
return new DHComponents(x, p, g, l, key);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IOException("Error parsing key encoding", e);
|
||||
} finally {
|
||||
if (val != null) {
|
||||
val.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generates the ASN.1 encoding
|
||||
private static byte[] encode(BigInteger p, BigInteger g, int l,
|
||||
byte[] key) {
|
||||
DerOutputStream tmp = new DerOutputStream();
|
||||
|
||||
// version
|
||||
tmp.putInteger(PKCS8_VERSION);
|
||||
|
||||
// privateKeyAlgorithm
|
||||
DerOutputStream algid = new DerOutputStream();
|
||||
|
||||
// store OID
|
||||
algid.putOID(DHPublicKey.DH_OID);
|
||||
// encode parameters
|
||||
DerOutputStream params = new DerOutputStream();
|
||||
params.putInteger(p);
|
||||
params.putInteger(g);
|
||||
if (l != 0) {
|
||||
params.putInteger(l);
|
||||
}
|
||||
// wrap parameters into SEQUENCE
|
||||
DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
|
||||
params.toByteArray());
|
||||
// store parameter SEQUENCE in algid
|
||||
algid.putDerValue(paramSequence);
|
||||
// wrap algid into SEQUENCE
|
||||
tmp.write(DerValue.tag_Sequence, algid);
|
||||
|
||||
// privateKey
|
||||
tmp.putOctetString(key);
|
||||
|
||||
// make it a SEQUENCE
|
||||
DerValue val = DerValue.wrap(DerValue.tag_Sequence, tmp);
|
||||
byte[] encoded = val.toByteArray();
|
||||
val.clear();
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a DH private key out of a private value <code>x</code>, a prime
|
||||
* modulus <code>p</code>, and a base generator <code>g</code>.
|
||||
|
@ -79,7 +205,7 @@ final class DHPrivateKey implements PrivateKey,
|
|||
* @param g the base generator
|
||||
*/
|
||||
DHPrivateKey(BigInteger x, BigInteger p, BigInteger g)
|
||||
throws InvalidKeyException {
|
||||
throws InvalidKeyException {
|
||||
this(x, p, g, 0);
|
||||
}
|
||||
|
||||
|
@ -98,12 +224,16 @@ final class DHPrivateKey implements PrivateKey,
|
|||
this.p = p;
|
||||
this.g = g;
|
||||
this.l = l;
|
||||
|
||||
byte[] xbytes = x.toByteArray();
|
||||
DerValue val = new DerValue(DerValue.tag_Integer, xbytes);
|
||||
this.key = val.toByteArray();
|
||||
val.clear();
|
||||
Arrays.fill(xbytes, (byte) 0);
|
||||
encode();
|
||||
try {
|
||||
this.key = val.toByteArray();
|
||||
} finally {
|
||||
val.clear();
|
||||
Arrays.fill(xbytes, (byte) 0);
|
||||
}
|
||||
this.encodedKey = encode(p, g, l, key);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,75 +245,18 @@ final class DHPrivateKey implements PrivateKey,
|
|||
* a Diffie-Hellman private key
|
||||
*/
|
||||
DHPrivateKey(byte[] encodedKey) throws InvalidKeyException {
|
||||
DerValue val = null;
|
||||
this.encodedKey = encodedKey.clone();
|
||||
DHComponents dc;
|
||||
try {
|
||||
val = new DerValue(encodedKey);
|
||||
if (val.tag != DerValue.tag_Sequence) {
|
||||
throw new InvalidKeyException ("Key not a SEQUENCE");
|
||||
}
|
||||
|
||||
//
|
||||
// version
|
||||
//
|
||||
BigInteger parsedVersion = val.data.getBigInteger();
|
||||
if (!parsedVersion.equals(PKCS8_VERSION)) {
|
||||
throw new IOException("version mismatch: (supported: " +
|
||||
PKCS8_VERSION + ", parsed: " +
|
||||
parsedVersion);
|
||||
}
|
||||
|
||||
//
|
||||
// privateKeyAlgorithm
|
||||
//
|
||||
DerValue algid = val.data.getDerValue();
|
||||
if (algid.tag != DerValue.tag_Sequence) {
|
||||
throw new InvalidKeyException("AlgId is not a SEQUENCE");
|
||||
}
|
||||
DerInputStream derInStream = algid.toDerInputStream();
|
||||
ObjectIdentifier oid = derInStream.getOID();
|
||||
if (oid == null) {
|
||||
throw new InvalidKeyException("Null OID");
|
||||
}
|
||||
if (derInStream.available() == 0) {
|
||||
throw new InvalidKeyException("Parameters missing");
|
||||
}
|
||||
// parse the parameters
|
||||
DerValue params = derInStream.getDerValue();
|
||||
if (params.tag == DerValue.tag_Null) {
|
||||
throw new InvalidKeyException("Null parameters");
|
||||
}
|
||||
if (params.tag != DerValue.tag_Sequence) {
|
||||
throw new InvalidKeyException("Parameters not a SEQUENCE");
|
||||
}
|
||||
params.data.reset();
|
||||
this.p = params.data.getBigInteger();
|
||||
this.g = params.data.getBigInteger();
|
||||
// Private-value length is OPTIONAL
|
||||
if (params.data.available() != 0) {
|
||||
this.l = params.data.getInteger();
|
||||
} else {
|
||||
this.l = 0;
|
||||
}
|
||||
if (params.data.available() != 0) {
|
||||
throw new InvalidKeyException("Extra parameter data");
|
||||
}
|
||||
|
||||
//
|
||||
// privateKey
|
||||
//
|
||||
this.key = val.data.getOctetString();
|
||||
|
||||
DerInputStream in = new DerInputStream(this.key);
|
||||
this.x = in.getBigInteger();
|
||||
|
||||
this.encodedKey = encodedKey.clone();
|
||||
} catch (IOException | NumberFormatException e) {
|
||||
throw new InvalidKeyException("Error parsing key encoding", e);
|
||||
} finally {
|
||||
if (val != null) {
|
||||
val.clear();
|
||||
}
|
||||
dc = decode(this.encodedKey);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidKeyException("Invalid encoding", e);
|
||||
}
|
||||
this.x = dc.x;
|
||||
this.p = dc.p;
|
||||
this.g = dc.g;
|
||||
this.l = dc.l;
|
||||
this.key = dc.key;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -204,55 +277,9 @@ final class DHPrivateKey implements PrivateKey,
|
|||
* Get the encoding of the key.
|
||||
*/
|
||||
public synchronized byte[] getEncoded() {
|
||||
encode();
|
||||
return encodedKey.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the encodedKey field if it has not been calculated.
|
||||
* Could generate null.
|
||||
*/
|
||||
private void encode() {
|
||||
if (this.encodedKey == null) {
|
||||
DerOutputStream tmp = new DerOutputStream();
|
||||
|
||||
//
|
||||
// version
|
||||
//
|
||||
tmp.putInteger(PKCS8_VERSION);
|
||||
|
||||
//
|
||||
// privateKeyAlgorithm
|
||||
//
|
||||
DerOutputStream algid = new DerOutputStream();
|
||||
|
||||
// store OID
|
||||
algid.putOID(DHPublicKey.DH_OID);
|
||||
// encode parameters
|
||||
DerOutputStream params = new DerOutputStream();
|
||||
params.putInteger(this.p);
|
||||
params.putInteger(this.g);
|
||||
if (this.l != 0) {
|
||||
params.putInteger(this.l);
|
||||
}
|
||||
// wrap parameters into SEQUENCE
|
||||
DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
|
||||
params.toByteArray());
|
||||
// store parameter SEQUENCE in algid
|
||||
algid.putDerValue(paramSequence);
|
||||
// wrap algid into SEQUENCE
|
||||
tmp.write(DerValue.tag_Sequence, algid);
|
||||
|
||||
// privateKey
|
||||
tmp.putOctetString(this.key);
|
||||
|
||||
// make it a SEQUENCE
|
||||
DerValue val = DerValue.wrap(DerValue.tag_Sequence, tmp);
|
||||
this.encodedKey = val.toByteArray();
|
||||
val.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the private value, <code>x</code>.
|
||||
*
|
||||
|
@ -307,10 +334,7 @@ final class DHPrivateKey implements PrivateKey,
|
|||
*/
|
||||
@java.io.Serial
|
||||
private Object writeReplace() throws java.io.ObjectStreamException {
|
||||
encode();
|
||||
return new KeyRep(KeyRep.Type.PRIVATE,
|
||||
getAlgorithm(),
|
||||
getFormat(),
|
||||
return new KeyRep(KeyRep.Type.PRIVATE, getAlgorithm(), getFormat(),
|
||||
encodedKey);
|
||||
}
|
||||
|
||||
|
@ -330,11 +354,28 @@ final class DHPrivateKey implements PrivateKey,
|
|||
if ((key == null) || (key.length == 0)) {
|
||||
throw new InvalidObjectException("key not deserializable");
|
||||
}
|
||||
this.key = key.clone();
|
||||
if ((encodedKey == null) || (encodedKey.length == 0)) {
|
||||
throw new InvalidObjectException(
|
||||
"encoded key not deserializable");
|
||||
}
|
||||
this.encodedKey = encodedKey.clone();
|
||||
// check if the "encodedKey" value matches the deserialized fields
|
||||
DHComponents c;
|
||||
byte[] encodedKeyIntern = encodedKey.clone();
|
||||
try {
|
||||
c = decode(encodedKeyIntern);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidObjectException("Invalid encoding", e);
|
||||
}
|
||||
if (!Arrays.equals(c.key, key) || !c.x.equals(x) || !c.p.equals(p)
|
||||
|| !c.g.equals(g) || c.l != l) {
|
||||
throw new InvalidObjectException(
|
||||
"encoded key not matching internal fields");
|
||||
}
|
||||
// zero out external arrays
|
||||
Arrays.fill(key, (byte)0x00);
|
||||
Arrays.fill(encodedKey, (byte)0x00);
|
||||
// use self-created internal copies
|
||||
this.key = c.key;
|
||||
this.encodedKey = encodedKeyIntern;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -26,6 +26,7 @@
|
|||
package com.sun.crypto.provider;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyRep;
|
||||
|
@ -70,6 +71,116 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
|
|||
static final ObjectIdentifier DH_OID =
|
||||
ObjectIdentifier.of(KnownOIDs.DiffieHellman);
|
||||
|
||||
private static class DHComponents {
|
||||
final BigInteger y;
|
||||
final BigInteger p;
|
||||
final BigInteger g;
|
||||
final int l;
|
||||
final byte[] key;
|
||||
|
||||
DHComponents(BigInteger y, BigInteger p, BigInteger g, int l,
|
||||
byte[] key) {
|
||||
this.y = y;
|
||||
this.p = p;
|
||||
this.g = g;
|
||||
this.l = l;
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
|
||||
// parses the specified encoding into a DHComponents object
|
||||
private static DHComponents decode(byte[] encodedKey)
|
||||
throws IOException {
|
||||
DerValue val = null;
|
||||
|
||||
try {
|
||||
val = new DerValue(encodedKey);
|
||||
if (val.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("Invalid key format");
|
||||
}
|
||||
|
||||
// algorithm identifier
|
||||
DerValue algid = val.data.getDerValue();
|
||||
if (algid.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("AlgId is not a SEQUENCE");
|
||||
}
|
||||
DerInputStream derInStream = algid.toDerInputStream();
|
||||
ObjectIdentifier oid = derInStream.getOID();
|
||||
if (oid == null) {
|
||||
throw new IOException("Null OID");
|
||||
}
|
||||
if (derInStream.available() == 0) {
|
||||
throw new IOException("Parameters missing");
|
||||
}
|
||||
|
||||
// parse the parameters
|
||||
DerValue params = derInStream.getDerValue();
|
||||
if (params.tag == DerValue.tag_Null) {
|
||||
throw new IOException("Null parameters");
|
||||
}
|
||||
if (params.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("Parameters not a SEQUENCE");
|
||||
}
|
||||
params.data.reset();
|
||||
|
||||
BigInteger p = params.data.getBigInteger();
|
||||
BigInteger g = params.data.getBigInteger();
|
||||
// Private-value length is OPTIONAL
|
||||
int l = (params.data.available() != 0 ? params.data.getInteger() :
|
||||
0);
|
||||
if (params.data.available() != 0) {
|
||||
throw new IOException("Extra parameter data");
|
||||
}
|
||||
|
||||
// publickey
|
||||
byte[] key = val.data.getBitString();
|
||||
DerInputStream in = new DerInputStream(key);
|
||||
BigInteger y = in.getBigInteger();
|
||||
|
||||
if (val.data.available() != 0) {
|
||||
throw new IOException("Excess key data");
|
||||
}
|
||||
return new DHComponents(y, p, g, l, key);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IOException("Error parsing key encoding", e);
|
||||
}
|
||||
}
|
||||
|
||||
// generates the ASN.1 encoding
|
||||
private static byte[] encode(BigInteger p, BigInteger g, int l,
|
||||
byte[] key) {
|
||||
DerOutputStream algid = new DerOutputStream();
|
||||
|
||||
// store oid in algid
|
||||
algid.putOID(DH_OID);
|
||||
|
||||
// encode parameters
|
||||
DerOutputStream params = new DerOutputStream();
|
||||
params.putInteger(p);
|
||||
params.putInteger(g);
|
||||
if (l != 0) {
|
||||
params.putInteger(l);
|
||||
}
|
||||
|
||||
// wrap parameters into SEQUENCE
|
||||
DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
|
||||
params.toByteArray());
|
||||
// store parameter SEQUENCE in algid
|
||||
algid.putDerValue(paramSequence);
|
||||
|
||||
// wrap algid into SEQUENCE, and store it in key encoding
|
||||
DerOutputStream tmpDerKey = new DerOutputStream();
|
||||
tmpDerKey.write(DerValue.tag_Sequence, algid);
|
||||
|
||||
// store key data
|
||||
tmpDerKey.putBitString(key);
|
||||
|
||||
// wrap algid and key into SEQUENCE
|
||||
DerOutputStream derKey = new DerOutputStream();
|
||||
derKey.write(DerValue.tag_Sequence, tmpDerKey);
|
||||
return derKey.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a DH public key out of a public value <code>y</code>, a prime
|
||||
* modulus <code>p</code>, and a base generator <code>g</code>.
|
||||
|
@ -102,7 +213,7 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
|
|||
this.l = l;
|
||||
this.key = new DerValue(DerValue.tag_Integer,
|
||||
this.y.toByteArray()).toByteArray();
|
||||
this.encodedKey = getEncoded();
|
||||
this.encodedKey = encode(p, g, l, key);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,68 +225,19 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
|
|||
* a Diffie-Hellman public key
|
||||
*/
|
||||
DHPublicKey(byte[] encodedKey) throws InvalidKeyException {
|
||||
InputStream inStream = new ByteArrayInputStream(encodedKey);
|
||||
this.encodedKey = encodedKey.clone();
|
||||
|
||||
DHComponents dc;
|
||||
try {
|
||||
DerValue derKeyVal = new DerValue(inStream);
|
||||
if (derKeyVal.tag != DerValue.tag_Sequence) {
|
||||
throw new InvalidKeyException ("Invalid key format");
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the algorithm identifier
|
||||
*/
|
||||
DerValue algid = derKeyVal.data.getDerValue();
|
||||
if (algid.tag != DerValue.tag_Sequence) {
|
||||
throw new InvalidKeyException("AlgId is not a SEQUENCE");
|
||||
}
|
||||
DerInputStream derInStream = algid.toDerInputStream();
|
||||
ObjectIdentifier oid = derInStream.getOID();
|
||||
if (oid == null) {
|
||||
throw new InvalidKeyException("Null OID");
|
||||
}
|
||||
if (derInStream.available() == 0) {
|
||||
throw new InvalidKeyException("Parameters missing");
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the parameters
|
||||
*/
|
||||
DerValue params = derInStream.getDerValue();
|
||||
if (params.tag == DerValue.tag_Null) {
|
||||
throw new InvalidKeyException("Null parameters");
|
||||
}
|
||||
if (params.tag != DerValue.tag_Sequence) {
|
||||
throw new InvalidKeyException("Parameters not a SEQUENCE");
|
||||
}
|
||||
params.data.reset();
|
||||
this.p = params.data.getBigInteger();
|
||||
this.g = params.data.getBigInteger();
|
||||
// Private-value length is OPTIONAL
|
||||
if (params.data.available() != 0) {
|
||||
this.l = params.data.getInteger();
|
||||
} else {
|
||||
this.l = 0;
|
||||
}
|
||||
if (params.data.available() != 0) {
|
||||
throw new InvalidKeyException("Extra parameter data");
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the key
|
||||
*/
|
||||
this.key = derKeyVal.data.getBitString();
|
||||
|
||||
DerInputStream in = new DerInputStream(this.key);
|
||||
this.y = in.getBigInteger();
|
||||
|
||||
if (derKeyVal.data.available() != 0) {
|
||||
throw new InvalidKeyException("Excess key data");
|
||||
}
|
||||
|
||||
this.encodedKey = encodedKey.clone();
|
||||
} catch (IOException | NumberFormatException e) {
|
||||
throw new InvalidKeyException("Error parsing key encoding", e);
|
||||
dc = decode(this.encodedKey);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidKeyException("Invalid encoding", e);
|
||||
}
|
||||
this.y = dc.y;
|
||||
this.p = dc.p;
|
||||
this.g = dc.g;
|
||||
this.l = dc.l;
|
||||
this.key = dc.key;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -196,37 +258,6 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
|
|||
* Get the encoding of the key.
|
||||
*/
|
||||
public synchronized byte[] getEncoded() {
|
||||
if (this.encodedKey == null) {
|
||||
DerOutputStream algid = new DerOutputStream();
|
||||
|
||||
// store oid in algid
|
||||
algid.putOID(DH_OID);
|
||||
|
||||
// encode parameters
|
||||
DerOutputStream params = new DerOutputStream();
|
||||
params.putInteger(this.p);
|
||||
params.putInteger(this.g);
|
||||
if (this.l != 0) {
|
||||
params.putInteger(this.l);
|
||||
}
|
||||
// wrap parameters into SEQUENCE
|
||||
DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
|
||||
params.toByteArray());
|
||||
// store parameter SEQUENCE in algid
|
||||
algid.putDerValue(paramSequence);
|
||||
|
||||
// wrap algid into SEQUENCE, and store it in key encoding
|
||||
DerOutputStream tmpDerKey = new DerOutputStream();
|
||||
tmpDerKey.write(DerValue.tag_Sequence, algid);
|
||||
|
||||
// store key data
|
||||
tmpDerKey.putBitString(this.key);
|
||||
|
||||
// wrap algid and key into SEQUENCE
|
||||
DerOutputStream derKey = new DerOutputStream();
|
||||
derKey.write(DerValue.tag_Sequence, tmpDerKey);
|
||||
this.encodedKey = derKey.toByteArray();
|
||||
}
|
||||
return this.encodedKey.clone();
|
||||
}
|
||||
|
||||
|
@ -263,8 +294,9 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
|
|||
+ Debug.toHexString(this.p)
|
||||
+ LINE_SEP + "g:" + LINE_SEP
|
||||
+ Debug.toHexString(this.g));
|
||||
if (this.l != 0)
|
||||
if (this.l != 0) {
|
||||
sb.append(LINE_SEP + "l:" + LINE_SEP + " " + this.l);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
@ -304,7 +336,7 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
|
|||
return new KeyRep(KeyRep.Type.PUBLIC,
|
||||
getAlgorithm(),
|
||||
getFormat(),
|
||||
getEncoded());
|
||||
encodedKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -323,11 +355,28 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
|
|||
if ((key == null) || (key.length == 0)) {
|
||||
throw new InvalidObjectException("key not deserializable");
|
||||
}
|
||||
this.key = key.clone();
|
||||
if ((encodedKey == null) || (encodedKey.length == 0)) {
|
||||
throw new InvalidObjectException(
|
||||
"encoded key not deserializable");
|
||||
}
|
||||
this.encodedKey = encodedKey.clone();
|
||||
// check if the "encodedKey" value matches the deserialized fields
|
||||
DHComponents c;
|
||||
byte[] encodedKeyIntern = encodedKey.clone();
|
||||
try {
|
||||
c = decode(encodedKeyIntern);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidObjectException("Invalid encoding", e);
|
||||
}
|
||||
if (!Arrays.equals(c.key, key) || !c.y.equals(y) || !c.p.equals(p)
|
||||
|| !c.g.equals(g) || c.l != l) {
|
||||
throw new InvalidObjectException(
|
||||
"encoded key not matching internal fields");
|
||||
}
|
||||
// zero out external arrays
|
||||
Arrays.fill(key, (byte)0x00);
|
||||
Arrays.fill(encodedKey, (byte)0x00);
|
||||
// use self-created internal copies
|
||||
this.key = c.key;
|
||||
this.encodedKey = encodedKeyIntern;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -194,22 +194,24 @@ public final class TlsMasterSecretGenerator extends KeyGeneratorSpi {
|
|||
return key.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
*
|
||||
* @param stream the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
@java.io.Serial
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
if ((key == null) || (key.length == 0)) {
|
||||
throw new InvalidObjectException("TlsMasterSecretKey is null");
|
||||
}
|
||||
key = key.clone();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
*
|
||||
* @param stream the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
@java.io.Serial
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
if (key == null || key.length == 0) {
|
||||
throw new InvalidObjectException("TlsMasterSecretKey is null");
|
||||
}
|
||||
byte[] temp = key;
|
||||
this.key = temp.clone();
|
||||
Arrays.fill(temp, (byte)0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -253,6 +253,15 @@ to determine the proxy that should be used for connecting to a given URI.</P>
|
|||
</OL>
|
||||
<P>The channel binding tokens generated are of the type "tls-server-end-point" as defined in
|
||||
RFC 5929.</P>
|
||||
|
||||
<LI><P><B>{@systemProperty jdk.http.maxHeaderSize}</B> (default: 393216 or 384kB)<BR>
|
||||
This is the maximum header field section size that a client is prepared to accept.
|
||||
This is computed as the sum of the size of the uncompressed header name, plus
|
||||
the size of the uncompressed header value, plus an overhead of 32 bytes for
|
||||
each field section line. If a peer sends a field section that exceeds this
|
||||
size a {@link java.net.ProtocolException ProtocolException} will be raised.
|
||||
This applies to all versions of the HTTP protocol. A value of zero or a negative
|
||||
value means no limit. If left unspecified, the default value is 393216 bytes.
|
||||
</UL>
|
||||
<P>All these properties are checked only once at startup.</P>
|
||||
<a id="AddressCache"></a>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -407,6 +407,11 @@ implements Serializable
|
|||
@SuppressWarnings("unchecked")
|
||||
Hashtable<Class<?>, PermissionCollection> perms =
|
||||
(Hashtable<Class<?>, PermissionCollection>)gfields.get("perms", null);
|
||||
|
||||
if (perms == null) {
|
||||
throw new InvalidObjectException("perms can't be null");
|
||||
}
|
||||
|
||||
permsMap = new ConcurrentHashMap<>(perms.size()*2);
|
||||
permsMap.putAll(perms);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -152,20 +152,20 @@ public final class SignedObject implements Serializable {
|
|||
*/
|
||||
public SignedObject(Serializable object, PrivateKey signingKey,
|
||||
Signature signingEngine)
|
||||
throws IOException, InvalidKeyException, SignatureException {
|
||||
// creating a stream pipe-line, from a to b
|
||||
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||
ObjectOutput a = new ObjectOutputStream(b);
|
||||
throws IOException, InvalidKeyException, SignatureException {
|
||||
// creating a stream pipe-line, from a to b
|
||||
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||
ObjectOutput a = new ObjectOutputStream(b);
|
||||
|
||||
// write and flush the object content to byte array
|
||||
a.writeObject(object);
|
||||
a.flush();
|
||||
a.close();
|
||||
this.content = b.toByteArray();
|
||||
b.close();
|
||||
// write and flush the object content to byte array
|
||||
a.writeObject(object);
|
||||
a.flush();
|
||||
a.close();
|
||||
this.content = b.toByteArray();
|
||||
b.close();
|
||||
|
||||
// now sign the encapsulated object
|
||||
this.sign(signingKey, signingEngine);
|
||||
// now sign the encapsulated object
|
||||
this.sign(signingKey, signingEngine);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -245,12 +245,12 @@ public final class SignedObject implements Serializable {
|
|||
* @throws SignatureException if signing fails.
|
||||
*/
|
||||
private void sign(PrivateKey signingKey, Signature signingEngine)
|
||||
throws InvalidKeyException, SignatureException {
|
||||
// initialize the signing engine
|
||||
signingEngine.initSign(signingKey);
|
||||
signingEngine.update(this.content.clone());
|
||||
this.signature = signingEngine.sign().clone();
|
||||
this.thealgorithm = signingEngine.getAlgorithm();
|
||||
throws InvalidKeyException, SignatureException {
|
||||
// initialize the signing engine
|
||||
signingEngine.initSign(signingKey);
|
||||
signingEngine.update(this.content.clone());
|
||||
this.signature = signingEngine.sign();
|
||||
this.thealgorithm = signingEngine.getAlgorithm();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -263,10 +263,16 @@ public final class SignedObject implements Serializable {
|
|||
*/
|
||||
@Serial
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
ObjectInputStream.GetField fields = s.readFields();
|
||||
content = ((byte[])fields.get("content", null)).clone();
|
||||
signature = ((byte[])fields.get("signature", null)).clone();
|
||||
thealgorithm = (String)fields.get("thealgorithm", null);
|
||||
throws IOException, ClassNotFoundException {
|
||||
ObjectInputStream.GetField fields = s.readFields();
|
||||
byte[] c = (byte[]) fields.get("content", null);
|
||||
byte[] sig = (byte[]) fields.get("signature", null);
|
||||
String a = (String) fields.get("thealgorithm", null);
|
||||
if (c == null || sig == null || a == null) {
|
||||
throw new InvalidObjectException("One or more null fields");
|
||||
}
|
||||
content = c.clone();
|
||||
signature = sig.clone();
|
||||
thealgorithm = a;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -27,6 +27,7 @@ package java.security;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.Serializable;
|
||||
import java.security.cert.CertPath;
|
||||
import java.security.cert.Certificate;
|
||||
|
@ -78,7 +79,7 @@ public final class Timestamp implements Serializable {
|
|||
* {@code null}.
|
||||
*/
|
||||
public Timestamp(Date timestamp, CertPath signerCertPath) {
|
||||
if (timestamp == null || signerCertPath == null) {
|
||||
if (isNull(timestamp, signerCertPath)) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.timestamp = new Date(timestamp.getTime()); // clone
|
||||
|
@ -166,9 +167,16 @@ public final class Timestamp implements Serializable {
|
|||
*/
|
||||
@java.io.Serial
|
||||
private void readObject(ObjectInputStream ois)
|
||||
throws IOException, ClassNotFoundException {
|
||||
throws IOException, ClassNotFoundException {
|
||||
ois.defaultReadObject();
|
||||
if (isNull(timestamp, signerCertPath)) {
|
||||
throw new InvalidObjectException("Invalid null field(s)");
|
||||
}
|
||||
myhash = -1;
|
||||
timestamp = new Date(timestamp.getTime());
|
||||
}
|
||||
|
||||
private static boolean isNull(Date d, CertPath c) {
|
||||
return (d == null || c == null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -29,6 +29,7 @@ import java.io.IOException;
|
|||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamField;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
@ -196,23 +197,32 @@ implements java.io.Serializable
|
|||
ObjectInputStream.GetField gfields = in.readFields();
|
||||
|
||||
// Get permissions
|
||||
@SuppressWarnings("unchecked")
|
||||
// writeObject writes a Hashtable<String, Vector<UnresolvedPermission>>
|
||||
// for the permissions key, so this cast is safe, unless the data is corrupt.
|
||||
Hashtable<String, Vector<UnresolvedPermission>> permissions =
|
||||
(Hashtable<String, Vector<UnresolvedPermission>>)
|
||||
gfields.get("permissions", null);
|
||||
perms = new ConcurrentHashMap<>(permissions.size()*2);
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Hashtable<String, Vector<UnresolvedPermission>> permissions =
|
||||
(Hashtable<String, Vector<UnresolvedPermission>>)
|
||||
gfields.get("permissions", null);
|
||||
|
||||
// Convert each entry (Vector) into a List
|
||||
Set<Map.Entry<String, Vector<UnresolvedPermission>>> set = permissions.entrySet();
|
||||
for (Map.Entry<String, Vector<UnresolvedPermission>> e : set) {
|
||||
// Convert Vector into ArrayList
|
||||
Vector<UnresolvedPermission> vec = e.getValue();
|
||||
List<UnresolvedPermission> list = new CopyOnWriteArrayList<>(vec);
|
||||
if (permissions == null) {
|
||||
throw new InvalidObjectException("Invalid null permissions");
|
||||
}
|
||||
|
||||
// Add to Hashtable being serialized
|
||||
perms.put(e.getKey(), list);
|
||||
perms = new ConcurrentHashMap<>(permissions.size()*2);
|
||||
|
||||
// Convert each entry (Vector) into a List
|
||||
Set<Map.Entry<String, Vector<UnresolvedPermission>>> set = permissions.entrySet();
|
||||
for (Map.Entry<String, Vector<UnresolvedPermission>> e : set) {
|
||||
// Convert Vector into ArrayList
|
||||
Vector<UnresolvedPermission> vec = e.getValue();
|
||||
List<UnresolvedPermission> list = new CopyOnWriteArrayList<>(vec);
|
||||
|
||||
// Add to Hashtable being serialized
|
||||
perms.put(e.getKey(), list);
|
||||
}
|
||||
} catch (ClassCastException cce) {
|
||||
throw new InvalidObjectException("Invalid type for permissions");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -28,6 +28,7 @@ package java.security.cert;
|
|||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
@ -70,6 +71,13 @@ public class CertificateRevokedException extends CertificateException {
|
|||
|
||||
private transient Map<String, Extension> extensions;
|
||||
|
||||
private static boolean isNull(Date revocationDate,
|
||||
CRLReason reason, X500Principal authority,
|
||||
Map<String, Extension> extensions) {
|
||||
return (revocationDate == null || reason == null || authority == null
|
||||
|| extensions == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code CertificateRevokedException} with
|
||||
* the specified revocation date, reason code, authority name, and map
|
||||
|
@ -92,8 +100,7 @@ public class CertificateRevokedException extends CertificateException {
|
|||
*/
|
||||
public CertificateRevokedException(Date revocationDate, CRLReason reason,
|
||||
X500Principal authority, Map<String, Extension> extensions) {
|
||||
if (revocationDate == null || reason == null || authority == null ||
|
||||
extensions == null) {
|
||||
if (isNull(revocationDate, reason, authority, extensions)) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.revocationDate = new Date(revocationDate.getTime());
|
||||
|
@ -234,9 +241,6 @@ public class CertificateRevokedException extends CertificateException {
|
|||
// (revocationDate, reason, authority)
|
||||
ois.defaultReadObject();
|
||||
|
||||
// Defensively copy the revocation date
|
||||
revocationDate = new Date(revocationDate.getTime());
|
||||
|
||||
// Read in the size (number of mappings) of the extensions map
|
||||
// and create the extensions map
|
||||
int size = ois.readInt();
|
||||
|
@ -247,6 +251,13 @@ public class CertificateRevokedException extends CertificateException {
|
|||
} else {
|
||||
extensions = HashMap.newHashMap(Math.min(size, 20));
|
||||
}
|
||||
// make sure all fields are set before checking
|
||||
if (isNull(revocationDate, reason, authority, extensions)) {
|
||||
throw new InvalidObjectException("Invalid null field(s)");
|
||||
}
|
||||
|
||||
// Defensively copy the revocation date
|
||||
revocationDate = new Date(revocationDate.getTime());
|
||||
|
||||
// Read in the extensions and put the mappings in the extensions map
|
||||
for (int i = 0; i < size; i++) {
|
||||
|
|
|
@ -41,6 +41,7 @@ package java.text;
|
|||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -1181,6 +1182,8 @@ public class MessageFormat extends Format {
|
|||
maximumArgumentNumber = argumentNumbers[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Constructors/applyPattern ensure that resultArray.length < MAX_ARGUMENT_INDEX
|
||||
Object[] resultArray = new Object[maximumArgumentNumber + 1];
|
||||
|
||||
int patternOffset = 0;
|
||||
|
@ -1459,6 +1462,9 @@ public class MessageFormat extends Format {
|
|||
* @serial
|
||||
*/
|
||||
private int[] argumentNumbers = new int[INITIAL_FORMATS];
|
||||
// Implementation limit for ArgumentIndex pattern element. Valid indices must
|
||||
// be less than this value
|
||||
private static final int MAX_ARGUMENT_INDEX = 10000;
|
||||
|
||||
/**
|
||||
* One less than the number of entries in {@code offsets}. Can also be thought of
|
||||
|
@ -1639,6 +1645,11 @@ public class MessageFormat extends Format {
|
|||
+ argumentNumber);
|
||||
}
|
||||
|
||||
if (argumentNumber >= MAX_ARGUMENT_INDEX) {
|
||||
throw new IllegalArgumentException(
|
||||
argumentNumber + " exceeds the ArgumentIndex implementation limit");
|
||||
}
|
||||
|
||||
// resize format information arrays if necessary
|
||||
if (offsetNumber >= formats.length) {
|
||||
int newLength = formats.length * 2;
|
||||
|
@ -2006,24 +2017,53 @@ public class MessageFormat extends Format {
|
|||
*/
|
||||
@java.io.Serial
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
in.defaultReadObject();
|
||||
boolean isValid = maxOffset >= -1
|
||||
&& formats.length > maxOffset
|
||||
&& offsets.length > maxOffset
|
||||
&& argumentNumbers.length > maxOffset;
|
||||
ObjectInputStream.GetField fields = in.readFields();
|
||||
if (fields.defaulted("argumentNumbers") || fields.defaulted("offsets")
|
||||
|| fields.defaulted("formats") || fields.defaulted("locale")
|
||||
|| fields.defaulted("pattern") || fields.defaulted("maxOffset")){
|
||||
throw new InvalidObjectException("Stream has missing data");
|
||||
}
|
||||
|
||||
locale = (Locale) fields.get("locale", null);
|
||||
String patt = (String) fields.get("pattern", null);
|
||||
int maxOff = fields.get("maxOffset", -2);
|
||||
int[] argNums = ((int[]) fields.get("argumentNumbers", null)).clone();
|
||||
int[] offs = ((int[]) fields.get("offsets", null)).clone();
|
||||
Format[] fmts = ((Format[]) fields.get("formats", null)).clone();
|
||||
|
||||
// Check arrays/maxOffset have correct value/length
|
||||
boolean isValid = maxOff >= -1 && argNums.length > maxOff
|
||||
&& offs.length > maxOff && fmts.length > maxOff;
|
||||
|
||||
// Check the correctness of arguments and offsets
|
||||
if (isValid) {
|
||||
int lastOffset = pattern.length() + 1;
|
||||
for (int i = maxOffset; i >= 0; --i) {
|
||||
if ((offsets[i] < 0) || (offsets[i] > lastOffset)) {
|
||||
int lastOffset = patt.length() + 1;
|
||||
for (int i = maxOff; i >= 0; --i) {
|
||||
if (argNums[i] < 0 || argNums[i] >= MAX_ARGUMENT_INDEX
|
||||
|| offs[i] < 0 || offs[i] > lastOffset) {
|
||||
isValid = false;
|
||||
break;
|
||||
} else {
|
||||
lastOffset = offsets[i];
|
||||
lastOffset = offs[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream.");
|
||||
throw new InvalidObjectException("Stream has invalid data");
|
||||
}
|
||||
maxOffset = maxOff;
|
||||
pattern = patt;
|
||||
offsets = offs;
|
||||
formats = fmts;
|
||||
argumentNumbers = argNums;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialization without data not supported for this class.
|
||||
*/
|
||||
@java.io.Serial
|
||||
private void readObjectNoData() throws ObjectStreamException {
|
||||
throw new InvalidObjectException("Deserialized MessageFormat objects need data");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -100,11 +100,9 @@ public class SecretKeySpec implements KeySpec, SecretKey {
|
|||
* is null or <code>key</code> is null or empty.
|
||||
*/
|
||||
public SecretKeySpec(byte[] key, String algorithm) {
|
||||
if (key == null || algorithm == null) {
|
||||
throw new IllegalArgumentException("Missing argument");
|
||||
}
|
||||
if (key.length == 0) {
|
||||
throw new IllegalArgumentException("Empty key");
|
||||
String errMsg = doSanityCheck(key, algorithm);
|
||||
if (errMsg != null) {
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
this.key = key.clone();
|
||||
this.algorithm = algorithm;
|
||||
|
@ -266,14 +264,22 @@ public class SecretKeySpec implements KeySpec, SecretKey {
|
|||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
String errMsg = doSanityCheck(key, algorithm);
|
||||
if (errMsg != null) {
|
||||
throw new InvalidObjectException(errMsg);
|
||||
}
|
||||
byte[] temp = key;
|
||||
this.key = temp.clone();
|
||||
Arrays.fill(temp, (byte) 0);
|
||||
}
|
||||
|
||||
private static String doSanityCheck(byte[] key, String algorithm) {
|
||||
String errMsg = null;
|
||||
if (key == null || algorithm == null) {
|
||||
throw new InvalidObjectException("Missing argument");
|
||||
}
|
||||
|
||||
this.key = key.clone();
|
||||
if (key.length == 0) {
|
||||
throw new InvalidObjectException("Invalid key length");
|
||||
errMsg = "Missing argument";
|
||||
} else if (key.length == 0) {
|
||||
errMsg = "Empty key";
|
||||
}
|
||||
return errMsg;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -102,20 +102,18 @@ public class ChoiceCallback implements Callback, java.io.Serializable {
|
|||
public ChoiceCallback(String prompt, String[] choices,
|
||||
int defaultChoice, boolean multipleSelectionsAllowed) {
|
||||
|
||||
if (prompt == null || prompt.isEmpty() ||
|
||||
choices == null || choices.length == 0 ||
|
||||
defaultChoice < 0 || defaultChoice >= choices.length)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
choices = (choices == null || choices.length == 0 ? choices :
|
||||
choices.clone());
|
||||
String errMsg = doSanityCheck(prompt, choices, defaultChoice,
|
||||
multipleSelectionsAllowed);
|
||||
if (errMsg != null) {
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
this.prompt = prompt;
|
||||
this.defaultChoice = defaultChoice;
|
||||
this.multipleSelectionsAllowed = multipleSelectionsAllowed;
|
||||
|
||||
this.choices = choices.clone();
|
||||
for (int i = 0; i < choices.length; i++) {
|
||||
if (choices[i] == null || choices[i].isEmpty())
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.choices = choices;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -183,9 +181,11 @@ public class ChoiceCallback implements Callback, java.io.Serializable {
|
|||
* @see #getSelectedIndexes
|
||||
*/
|
||||
public void setSelectedIndexes(int[] selections) {
|
||||
if (!multipleSelectionsAllowed)
|
||||
if (!multipleSelectionsAllowed) {
|
||||
throw new UnsupportedOperationException();
|
||||
this.selections = selections == null ? null : selections.clone();
|
||||
}
|
||||
this.selections = ((selections == null || selections.length == 0) ?
|
||||
selections : selections.clone());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -211,26 +211,35 @@ public class ChoiceCallback implements Callback, java.io.Serializable {
|
|||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
choices = (choices == null || choices.length == 0 ?
|
||||
choices : choices.clone());
|
||||
String errMsg = doSanityCheck(prompt, choices, defaultChoice,
|
||||
multipleSelectionsAllowed);
|
||||
if (errMsg != null) {
|
||||
throw new InvalidObjectException(errMsg);
|
||||
}
|
||||
|
||||
selections = (selections == null || selections.length == 0 ?
|
||||
selections : selections.clone());
|
||||
if (selections != null && selections.length > 1 &&
|
||||
!multipleSelectionsAllowed) {
|
||||
throw new InvalidObjectException("Multiple selections not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
private static String doSanityCheck(String prompt, String[] choices,
|
||||
int defaultChoice, boolean allowMultiple) {
|
||||
if ((prompt == null) || prompt.isEmpty() ||
|
||||
(choices == null) || (choices.length == 0) ||
|
||||
(defaultChoice < 0) || (defaultChoice >= choices.length)) {
|
||||
throw new InvalidObjectException(
|
||||
"Missing/invalid prompt/choices");
|
||||
return "Missing/invalid prompt/choices";
|
||||
}
|
||||
|
||||
choices = choices.clone();
|
||||
for (int i = 0; i < choices.length; i++) {
|
||||
if ((choices[i] == null) || choices[i].isEmpty())
|
||||
throw new InvalidObjectException("Null/empty choices");
|
||||
}
|
||||
|
||||
if (selections != null) {
|
||||
selections = selections.clone();
|
||||
if (!multipleSelectionsAllowed && (selections.length != 1)) {
|
||||
throw new InvalidObjectException(
|
||||
"Multiple selections not allowed");
|
||||
if ((choices[i] == null) || choices[i].isEmpty()) {
|
||||
return "Null/empty choices value";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -26,6 +26,7 @@
|
|||
package javax.security.auth.callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
|
||||
/**
|
||||
|
@ -189,25 +190,10 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
|
|||
*/
|
||||
public ConfirmationCallback(int messageType,
|
||||
int optionType, int defaultOption) {
|
||||
|
||||
if (messageType < INFORMATION || messageType > ERROR ||
|
||||
optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
switch (optionType) {
|
||||
case YES_NO_OPTION:
|
||||
if (defaultOption != YES && defaultOption != NO)
|
||||
throw new IllegalArgumentException();
|
||||
break;
|
||||
case YES_NO_CANCEL_OPTION:
|
||||
if (defaultOption != YES && defaultOption != NO &&
|
||||
defaultOption != CANCEL)
|
||||
throw new IllegalArgumentException();
|
||||
break;
|
||||
case OK_CANCEL_OPTION:
|
||||
if (defaultOption != OK && defaultOption != CANCEL)
|
||||
throw new IllegalArgumentException();
|
||||
break;
|
||||
String errMsg = doSanityCheck(messageType, optionType, false, null,
|
||||
defaultOption, null, false);
|
||||
if (errMsg != null) {
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
|
||||
this.prompt = null;
|
||||
|
@ -250,21 +236,20 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
|
|||
public ConfirmationCallback(int messageType,
|
||||
String[] options, int defaultOption) {
|
||||
|
||||
if (messageType < INFORMATION || messageType > ERROR ||
|
||||
options == null || options.length == 0 ||
|
||||
defaultOption < 0 || defaultOption >= options.length)
|
||||
throw new IllegalArgumentException();
|
||||
if (options != null) {
|
||||
options = options.clone();
|
||||
}
|
||||
String errMsg = doSanityCheck(messageType, UNSPECIFIED_OPTION, true,
|
||||
options, defaultOption, null, false);
|
||||
if (errMsg != null) {
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
|
||||
this.prompt = null;
|
||||
this.messageType = messageType;
|
||||
this.optionType = UNSPECIFIED_OPTION;
|
||||
this.defaultOption = defaultOption;
|
||||
|
||||
this.options = options.clone();
|
||||
for (int i = 0; i < options.length; i++) {
|
||||
if (options[i] == null || options[i].isEmpty())
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -304,27 +289,11 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
|
|||
public ConfirmationCallback(String prompt, int messageType,
|
||||
int optionType, int defaultOption) {
|
||||
|
||||
if (prompt == null || prompt.isEmpty() ||
|
||||
messageType < INFORMATION || messageType > ERROR ||
|
||||
optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
switch (optionType) {
|
||||
case YES_NO_OPTION:
|
||||
if (defaultOption != YES && defaultOption != NO)
|
||||
throw new IllegalArgumentException();
|
||||
break;
|
||||
case YES_NO_CANCEL_OPTION:
|
||||
if (defaultOption != YES && defaultOption != NO &&
|
||||
defaultOption != CANCEL)
|
||||
throw new IllegalArgumentException();
|
||||
break;
|
||||
case OK_CANCEL_OPTION:
|
||||
if (defaultOption != OK && defaultOption != CANCEL)
|
||||
throw new IllegalArgumentException();
|
||||
break;
|
||||
String errMsg = doSanityCheck(messageType, optionType, false, null,
|
||||
defaultOption, prompt, true);
|
||||
if (errMsg != null) {
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
|
||||
this.prompt = prompt;
|
||||
this.messageType = messageType;
|
||||
this.optionType = optionType;
|
||||
|
@ -369,22 +338,20 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
|
|||
public ConfirmationCallback(String prompt, int messageType,
|
||||
String[] options, int defaultOption) {
|
||||
|
||||
if (prompt == null || prompt.isEmpty() ||
|
||||
messageType < INFORMATION || messageType > ERROR ||
|
||||
options == null || options.length == 0 ||
|
||||
defaultOption < 0 || defaultOption >= options.length)
|
||||
throw new IllegalArgumentException();
|
||||
if (options != null) {
|
||||
options = options.clone();
|
||||
}
|
||||
String errMsg = doSanityCheck(messageType, UNSPECIFIED_OPTION, true,
|
||||
options, defaultOption, prompt, true);
|
||||
if (errMsg != null) {
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
|
||||
this.prompt = prompt;
|
||||
this.messageType = messageType;
|
||||
this.optionType = UNSPECIFIED_OPTION;
|
||||
this.defaultOption = defaultOption;
|
||||
|
||||
this.options = options.clone();
|
||||
for (int i = 0; i < options.length; i++) {
|
||||
if (options[i] == null || options[i].isEmpty())
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -491,6 +458,49 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
|
|||
return selection;
|
||||
}
|
||||
|
||||
private static String doSanityCheck(int msgType, int optionType,
|
||||
boolean isUnspecifiedOption, String[] options, int defOption,
|
||||
String prompt, boolean checkPrompt) {
|
||||
// validate msgType
|
||||
if (msgType < INFORMATION || msgType > ERROR) {
|
||||
return "Invalid msgType";
|
||||
}
|
||||
// validate prompt if checkPrompt == true
|
||||
if (checkPrompt && (prompt == null || prompt.isEmpty())) {
|
||||
return "Invalid prompt";
|
||||
}
|
||||
// validate optionType
|
||||
if (isUnspecifiedOption) {
|
||||
if (optionType != UNSPECIFIED_OPTION) {
|
||||
return "Invalid optionType";
|
||||
}
|
||||
// check options
|
||||
if (options == null || options.length == 0 ||
|
||||
defOption < 0 || defOption >= options.length) {
|
||||
return "Invalid options and/or default option";
|
||||
}
|
||||
for (String ov : options) {
|
||||
if (ov == null || ov.isEmpty()) {
|
||||
return "Invalid option value";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION) {
|
||||
return "Invalid optionType";
|
||||
}
|
||||
// validate defOption based on optionType
|
||||
if ((optionType == YES_NO_OPTION && (defOption != YES &&
|
||||
defOption != NO)) ||
|
||||
(optionType == YES_NO_CANCEL_OPTION && (defOption != YES &&
|
||||
defOption != NO && defOption != CANCEL)) ||
|
||||
(optionType == OK_CANCEL_OPTION && (defOption != OK &&
|
||||
defOption != CANCEL))) {
|
||||
return "Invalid default option";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
*
|
||||
|
@ -502,8 +512,15 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
|
|||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
|
||||
if (options != null) {
|
||||
options = options.clone();
|
||||
}
|
||||
String errMsg = doSanityCheck(messageType, optionType,
|
||||
(optionType == UNSPECIFIED_OPTION), options, defaultOption,
|
||||
prompt, false);
|
||||
if (errMsg != null) {
|
||||
throw new InvalidObjectException(errMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -178,7 +178,9 @@ public class PasswordCallback implements Callback, java.io.Serializable {
|
|||
}
|
||||
|
||||
if (inputPassword != null) {
|
||||
inputPassword = inputPassword.clone();
|
||||
char[] temp = inputPassword;
|
||||
inputPassword = temp.clone();
|
||||
Arrays.fill(temp, '0');
|
||||
cleanable = CleanerFactory.cleaner().register(
|
||||
this, cleanerFor(inputPassword));
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
package sun.net.www;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Array;
|
||||
import java.net.ProtocolException;
|
||||
import java.util.Collections;
|
||||
import java.util.*;
|
||||
|
||||
|
@ -45,11 +47,32 @@ public final class MessageHeader {
|
|||
private String[] values;
|
||||
private int nkeys;
|
||||
|
||||
// max number of bytes for headers, <=0 means unlimited;
|
||||
// this corresponds to the length of the names, plus the length
|
||||
// of the values, plus an overhead of 32 bytes per name: value
|
||||
// pair.
|
||||
// Note: we use the same definition as HTTP/2 SETTINGS_MAX_HEADER_LIST_SIZE
|
||||
// see RFC 9113, section 6.5.2.
|
||||
// https://www.rfc-editor.org/rfc/rfc9113.html#SETTINGS_MAX_HEADER_LIST_SIZE
|
||||
private final int maxHeaderSize;
|
||||
|
||||
// Aggregate size of the field lines (name + value + 32) x N
|
||||
// that have been parsed and accepted so far.
|
||||
// This is defined as a long to force promotion to long
|
||||
// and avoid overflows; see checkNewSize;
|
||||
private long size;
|
||||
|
||||
public MessageHeader () {
|
||||
this(0);
|
||||
}
|
||||
|
||||
public MessageHeader (int maxHeaderSize) {
|
||||
this.maxHeaderSize = maxHeaderSize;
|
||||
grow();
|
||||
}
|
||||
|
||||
public MessageHeader (InputStream is) throws java.io.IOException {
|
||||
maxHeaderSize = 0;
|
||||
parseHeader(is);
|
||||
}
|
||||
|
||||
|
@ -476,10 +499,28 @@ public final class MessageHeader {
|
|||
public void parseHeader(InputStream is) throws java.io.IOException {
|
||||
synchronized (this) {
|
||||
nkeys = 0;
|
||||
size = 0;
|
||||
}
|
||||
mergeHeader(is);
|
||||
}
|
||||
|
||||
private void checkMaxHeaderSize(int sz) throws ProtocolException {
|
||||
if (maxHeaderSize > 0) checkNewSize(size, sz, 0);
|
||||
}
|
||||
|
||||
private long checkNewSize(long size, int name, int value) throws ProtocolException {
|
||||
// See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2.
|
||||
long newSize = size + name + value + 32;
|
||||
if (maxHeaderSize > 0 && newSize > maxHeaderSize) {
|
||||
Arrays.fill(keys, 0, nkeys, null);
|
||||
Arrays.fill(values,0, nkeys, null);
|
||||
nkeys = 0;
|
||||
throw new ProtocolException(String.format("Header size too big: %s > %s",
|
||||
newSize, maxHeaderSize));
|
||||
}
|
||||
return newSize;
|
||||
}
|
||||
|
||||
/** Parse and merge a MIME header from an input stream. */
|
||||
@SuppressWarnings("fallthrough")
|
||||
public void mergeHeader(InputStream is) throws java.io.IOException {
|
||||
|
@ -493,7 +534,15 @@ public final class MessageHeader {
|
|||
int c;
|
||||
boolean inKey = firstc > ' ';
|
||||
s[len++] = (char) firstc;
|
||||
checkMaxHeaderSize(len);
|
||||
parseloop:{
|
||||
// We start parsing for a new name value pair here.
|
||||
// The max header size includes an overhead of 32 bytes per
|
||||
// name value pair.
|
||||
// See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2.
|
||||
long maxRemaining = maxHeaderSize > 0
|
||||
? maxHeaderSize - size - 32
|
||||
: Long.MAX_VALUE;
|
||||
while ((c = is.read()) >= 0) {
|
||||
switch (c) {
|
||||
case ':':
|
||||
|
@ -527,6 +576,9 @@ public final class MessageHeader {
|
|||
s = ns;
|
||||
}
|
||||
s[len++] = (char) c;
|
||||
if (maxHeaderSize > 0 && len > maxRemaining) {
|
||||
checkMaxHeaderSize(len);
|
||||
}
|
||||
}
|
||||
firstc = -1;
|
||||
}
|
||||
|
@ -548,6 +600,9 @@ public final class MessageHeader {
|
|||
v = new String();
|
||||
else
|
||||
v = String.copyValueOf(s, keyend, len - keyend);
|
||||
int klen = k == null ? 0 : k.length();
|
||||
|
||||
size = checkNewSize(size, klen, v.length());
|
||||
add(k, v);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,6 +172,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
|||
*/
|
||||
private static final int bufSize4ES;
|
||||
|
||||
private static final int maxHeaderSize;
|
||||
|
||||
/*
|
||||
* Restrict setting of request headers through the public api
|
||||
* consistent with JavaScript XMLHttpRequest2 with a few
|
||||
|
@ -288,6 +290,19 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
|||
} else {
|
||||
restrictedHeaderSet = null;
|
||||
}
|
||||
|
||||
int defMaxHeaderSize = 384 * 1024;
|
||||
String maxHeaderSizeStr = getNetProperty("jdk.http.maxHeaderSize");
|
||||
int maxHeaderSizeVal = defMaxHeaderSize;
|
||||
if (maxHeaderSizeStr != null) {
|
||||
try {
|
||||
maxHeaderSizeVal = Integer.parseInt(maxHeaderSizeStr);
|
||||
} catch (NumberFormatException n) {
|
||||
maxHeaderSizeVal = defMaxHeaderSize;
|
||||
}
|
||||
}
|
||||
if (maxHeaderSizeVal < 0) maxHeaderSizeVal = 0;
|
||||
maxHeaderSize = maxHeaderSizeVal;
|
||||
}
|
||||
|
||||
static final String httpVersion = "HTTP/1.1";
|
||||
|
@ -754,7 +769,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
|||
}
|
||||
ps = (PrintStream) http.getOutputStream();
|
||||
connected=true;
|
||||
responses = new MessageHeader();
|
||||
responses = new MessageHeader(maxHeaderSize);
|
||||
setRequests=false;
|
||||
writeRequests();
|
||||
}
|
||||
|
@ -912,7 +927,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
|||
throws IOException {
|
||||
super(checkURL(u));
|
||||
requests = new MessageHeader();
|
||||
responses = new MessageHeader();
|
||||
responses = new MessageHeader(maxHeaderSize);
|
||||
userHeaders = new MessageHeader();
|
||||
this.handler = handler;
|
||||
instProxy = p;
|
||||
|
@ -2810,7 +2825,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
|||
}
|
||||
|
||||
// clear out old response headers!!!!
|
||||
responses = new MessageHeader();
|
||||
responses = new MessageHeader(maxHeaderSize);
|
||||
if (stat == HTTP_USE_PROXY) {
|
||||
/* This means we must re-request the resource through the
|
||||
* proxy denoted in the "Location:" field of the response.
|
||||
|
@ -3000,7 +3015,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
|||
} catch (IOException e) { }
|
||||
}
|
||||
responseCode = -1;
|
||||
responses = new MessageHeader();
|
||||
responses = new MessageHeader(maxHeaderSize);
|
||||
connected = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -26,6 +26,7 @@
|
|||
package sun.security.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.security.AccessController;
|
||||
import java.security.DrbgParameters;
|
||||
import java.security.PrivilegedAction;
|
||||
|
@ -272,11 +273,18 @@ public final class DRBG extends SecureRandomSpi {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
*
|
||||
* @param s the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
@java.io.Serial
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject();
|
||||
if (mdp.mech == null) {
|
||||
if (mdp == null || mdp.mech == null) {
|
||||
throw new IllegalArgumentException("Input data is corrupted");
|
||||
}
|
||||
createImpl();
|
||||
|
|
|
@ -213,8 +213,6 @@ final class ClientHello {
|
|||
// ignore cookie
|
||||
hos.putBytes16(getEncodedCipherSuites());
|
||||
hos.putBytes8(compressionMethod);
|
||||
extensions.send(hos); // In TLS 1.3, use of certain
|
||||
// extensions is mandatory.
|
||||
} catch (IOException ioe) {
|
||||
// unlikely
|
||||
}
|
||||
|
@ -1426,6 +1424,9 @@ final class ClientHello {
|
|||
shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id,
|
||||
SSLHandshake.SERVER_HELLO);
|
||||
|
||||
// Reset the ClientHello non-zero offset fragment allowance
|
||||
shc.acceptCliHelloFragments = false;
|
||||
|
||||
//
|
||||
// produce
|
||||
//
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -40,12 +40,23 @@ import sun.security.ssl.SSLCipher.SSLReadCipher;
|
|||
final class DTLSInputRecord extends InputRecord implements DTLSRecord {
|
||||
private DTLSReassembler reassembler = null;
|
||||
private int readEpoch;
|
||||
private SSLContextImpl sslContext;
|
||||
|
||||
DTLSInputRecord(HandshakeHash handshakeHash) {
|
||||
super(handshakeHash, SSLReadCipher.nullDTlsReadCipher());
|
||||
this.readEpoch = 0;
|
||||
}
|
||||
|
||||
// Method to set TransportContext
|
||||
public void setTransportContext(TransportContext tc) {
|
||||
this.tc = tc;
|
||||
}
|
||||
|
||||
// Method to set SSLContext
|
||||
public void setSSLContext(SSLContextImpl sslContext) {
|
||||
this.sslContext = sslContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
void changeReadCiphers(SSLReadCipher readCipher) {
|
||||
this.readCipher = readCipher;
|
||||
|
@ -537,6 +548,27 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a sufficiently-large initial ClientHello fragment into one that
|
||||
* stops immediately after the compression methods. This is only used
|
||||
* for the initial CH message fragment at offset 0.
|
||||
*
|
||||
* @param srcFrag the fragment actually received by the DTLSReassembler
|
||||
* @param limit the size of the new, cloned/truncated handshake fragment
|
||||
*
|
||||
* @return a truncated handshake fragment that is sized to look like a
|
||||
* complete message, but actually contains only up to the compression
|
||||
* methods (no extensions)
|
||||
*/
|
||||
private static HandshakeFragment truncateChFragment(HandshakeFragment srcFrag,
|
||||
int limit) {
|
||||
return new HandshakeFragment(Arrays.copyOf(srcFrag.fragment, limit),
|
||||
srcFrag.contentType, srcFrag.majorVersion,
|
||||
srcFrag.minorVersion, srcFrag.recordEnS, srcFrag.recordEpoch,
|
||||
srcFrag.recordSeq, srcFrag.handshakeType, limit,
|
||||
srcFrag.messageSeq, srcFrag.fragmentOffset, limit);
|
||||
}
|
||||
|
||||
private static final class HoleDescriptor {
|
||||
int offset; // fragment_offset
|
||||
int limit; // fragment_offset + fragment_length
|
||||
|
@ -640,10 +672,17 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
|
|||
// Queue up a handshake message.
|
||||
void queueUpHandshake(HandshakeFragment hsf) throws SSLProtocolException {
|
||||
if (!isDesirable(hsf)) {
|
||||
// Not a dedired record, discard it.
|
||||
// Not a desired record, discard it.
|
||||
return;
|
||||
}
|
||||
|
||||
if (hsf.handshakeType == SSLHandshake.CLIENT_HELLO.id) {
|
||||
// validate the first or subsequent ClientHello message
|
||||
if ((hsf = valHello(hsf, hsf.messageSeq == 0)) == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up the retransmission messages if necessary.
|
||||
cleanUpRetransmit(hsf);
|
||||
|
||||
|
@ -769,6 +808,100 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
|
|||
}
|
||||
}
|
||||
|
||||
private HandshakeFragment valHello(HandshakeFragment hsf,
|
||||
boolean firstHello) {
|
||||
ServerHandshakeContext shc =
|
||||
(ServerHandshakeContext) tc.handshakeContext;
|
||||
// Drop any fragment that is not a zero offset until we've received
|
||||
// a second (or possibly later) CH message that passes the cookie
|
||||
// check.
|
||||
if (shc == null || !shc.acceptCliHelloFragments) {
|
||||
if (hsf.fragmentOffset != 0) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
// Let this fragment through to the DTLSReassembler as-is
|
||||
return hsf;
|
||||
}
|
||||
|
||||
try {
|
||||
ByteBuffer fragmentData = ByteBuffer.wrap(hsf.fragment);
|
||||
|
||||
ProtocolVersion pv = ProtocolVersion.valueOf(
|
||||
Record.getInt16(fragmentData));
|
||||
if (!pv.isDTLS) {
|
||||
return null;
|
||||
}
|
||||
// Read the random (32 bytes)
|
||||
if (fragmentData.remaining() < 32) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
|
||||
SSLLogger.fine("Rejected client hello fragment (bad random len) " +
|
||||
"fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
fragmentData.position(fragmentData.position() + 32);
|
||||
|
||||
// SessionID
|
||||
byte[] sessId = Record.getBytes8(fragmentData);
|
||||
if (sessId.length > 0 &&
|
||||
!SSLConfiguration.enableDtlsResumeCookie) {
|
||||
// If we are in a resumption it is possible that the cookie
|
||||
// exchange will be skipped. This is a server-side setting
|
||||
// and it is NOT the default. If enableDtlsResumeCookie is
|
||||
// false though, then we will buffer fragments since there
|
||||
// is no cookie exchange to execute prior to performing
|
||||
// reassembly.
|
||||
return hsf;
|
||||
}
|
||||
|
||||
// Cookie
|
||||
byte[] cookie = Record.getBytes8(fragmentData);
|
||||
if (firstHello && cookie.length != 0) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
|
||||
SSLLogger.fine("Rejected initial client hello fragment (bad cookie len) " +
|
||||
"fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// CipherSuites
|
||||
Record.getBytes16(fragmentData);
|
||||
// Compression methods
|
||||
Record.getBytes8(fragmentData);
|
||||
|
||||
// If it's the first fragment, we'll truncate it and push it
|
||||
// through the reassembler.
|
||||
if (firstHello) {
|
||||
return truncateChFragment(hsf, fragmentData.position());
|
||||
} else {
|
||||
HelloCookieManager hcMgr = sslContext.
|
||||
getHelloCookieManager(ProtocolVersion.DTLS10);
|
||||
ByteBuffer msgFragBuf = ByteBuffer.wrap(hsf.fragment, 0,
|
||||
fragmentData.position());
|
||||
ClientHello.ClientHelloMessage chMsg =
|
||||
new ClientHello.ClientHelloMessage(shc, msgFragBuf, null);
|
||||
if (!hcMgr.isCookieValid(shc, chMsg, cookie)) {
|
||||
// Bad cookie check, truncate it and let the ClientHello
|
||||
// consumer recheck, fail and take the appropriate action.
|
||||
return truncateChFragment(hsf, fragmentData.position());
|
||||
} else {
|
||||
// It's a good cookie, return the original handshake
|
||||
// fragment and let it go into the DTLSReassembler like
|
||||
// any other fragment so we can wait for the rest of
|
||||
// the CH message.
|
||||
shc.acceptCliHelloFragments = true;
|
||||
return hsf;
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
|
||||
SSLLogger.fine("Rejected client hello fragment " +
|
||||
"fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Queue up a ChangeCipherSpec message
|
||||
void queueUpChangeCipherSpec(RecordFragment rf)
|
||||
throws SSLProtocolException {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -55,6 +55,7 @@ class ServerHandshakeContext extends HandshakeContext {
|
|||
CertificateMessage.CertificateEntry currentCertEntry;
|
||||
private static final long DEFAULT_STATUS_RESP_DELAY = 5000L;
|
||||
final long statusRespTimeout;
|
||||
boolean acceptCliHelloFragments = false;
|
||||
|
||||
|
||||
ServerHandshakeContext(SSLContextImpl sslContext,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -156,6 +156,11 @@ final class TransportContext implements ConnectionContext {
|
|||
|
||||
this.acc = AccessController.getContext();
|
||||
this.consumers = new HashMap<>();
|
||||
|
||||
if (inputRecord instanceof DTLSInputRecord dtlsInputRecord) {
|
||||
dtlsInputRecord.setTransportContext(this);
|
||||
dtlsInputRecord.setSSLContext(this.sslContext);
|
||||
}
|
||||
}
|
||||
|
||||
// Dispatch plaintext to a specific consumer.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -127,13 +127,24 @@ public final class ObjectIdentifier implements Serializable {
|
|||
// Is the component's field calculated?
|
||||
private transient boolean componentsCalculated = false;
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
*
|
||||
* @param is the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
@java.io.Serial
|
||||
private void readObject(ObjectInputStream is)
|
||||
throws IOException, ClassNotFoundException {
|
||||
is.defaultReadObject();
|
||||
|
||||
if (encoding == null) { // from an old version
|
||||
int[] comp = (int[])components;
|
||||
if (components == null) {
|
||||
throw new InvalidObjectException("OID components is null");
|
||||
}
|
||||
|
||||
int[] comp = ((int[]) components).clone();
|
||||
if (componentLen > comp.length) {
|
||||
componentLen = comp.length;
|
||||
}
|
||||
|
@ -142,7 +153,9 @@ public final class ObjectIdentifier implements Serializable {
|
|||
// will be performed again in init().
|
||||
checkOidSize(componentLen);
|
||||
init(comp, componentLen);
|
||||
components = comp;
|
||||
} else {
|
||||
encoding = encoding.clone(); // defensive copying
|
||||
checkOidSize(encoding.length);
|
||||
check(encoding);
|
||||
}
|
||||
|
@ -261,6 +274,7 @@ public final class ObjectIdentifier implements Serializable {
|
|||
encoding = in.getDerValue().getOID().encoding;
|
||||
}
|
||||
|
||||
// set 'encoding' field based on the specified 'components' and 'length'
|
||||
private void init(int[] components, int length) throws IOException {
|
||||
int pos = 0;
|
||||
byte[] tmp = new byte[length * 5 + 1]; // +1 for empty input
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -25,11 +25,13 @@
|
|||
|
||||
package sun.security.x509;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.interfaces.DSAParams;
|
||||
|
||||
import java.util.Arrays;
|
||||
import sun.security.util.*;
|
||||
|
||||
|
||||
|
@ -72,33 +74,42 @@ import sun.security.util.*;
|
|||
*
|
||||
* @author David Brownell
|
||||
*/
|
||||
public final
|
||||
class AlgIdDSA extends AlgorithmId implements DSAParams
|
||||
{
|
||||
public final class AlgIdDSA extends AlgorithmId implements DSAParams {
|
||||
|
||||
@java.io.Serial
|
||||
private static final long serialVersionUID = 3437177836797504046L;
|
||||
|
||||
private static class DSAComponents {
|
||||
private final BigInteger p;
|
||||
private final BigInteger q;
|
||||
private final BigInteger g;
|
||||
DSAComponents(BigInteger p, BigInteger q, BigInteger g) {
|
||||
this.p = p;
|
||||
this.q = q;
|
||||
this.g = g;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The three unsigned integer parameters.
|
||||
*/
|
||||
private BigInteger p , q, g;
|
||||
private BigInteger p, q, g;
|
||||
|
||||
/** Returns the DSS/DSA parameter "P" */
|
||||
public BigInteger getP () { return p; }
|
||||
public BigInteger getP() { return p; }
|
||||
|
||||
/** Returns the DSS/DSA parameter "Q" */
|
||||
public BigInteger getQ () { return q; }
|
||||
public BigInteger getQ() { return q; }
|
||||
|
||||
/** Returns the DSS/DSA parameter "G" */
|
||||
public BigInteger getG () { return g; }
|
||||
public BigInteger getG() { return g; }
|
||||
|
||||
/**
|
||||
* Default constructor. The OID and parameters must be
|
||||
* deserialized before this algorithm ID is used.
|
||||
*/
|
||||
@Deprecated
|
||||
public AlgIdDSA () {}
|
||||
public AlgIdDSA() {}
|
||||
|
||||
/**
|
||||
* Constructs a DSS/DSA Algorithm ID from numeric parameters.
|
||||
|
@ -109,7 +120,7 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
|
|||
* @param q the DSS/DSA parameter "Q"
|
||||
* @param g the DSS/DSA parameter "G"
|
||||
*/
|
||||
public AlgIdDSA (BigInteger p, BigInteger q, BigInteger g) {
|
||||
public AlgIdDSA(BigInteger p, BigInteger q, BigInteger g) {
|
||||
super (DSA_oid);
|
||||
|
||||
if (p != null || q != null || g != null) {
|
||||
|
@ -120,8 +131,10 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
|
|||
this.p = p;
|
||||
this.q = q;
|
||||
this.g = g;
|
||||
initializeParams ();
|
||||
|
||||
// For algorithm IDs which haven't been created from a DER
|
||||
// encoded value, need to create DER encoding and store it
|
||||
// into "encodedParams"
|
||||
encodedParams = encode(p, q, g);
|
||||
} catch (IOException e) {
|
||||
/* this should not happen */
|
||||
throw new ProviderException ("Construct DSS/DSA Algorithm ID");
|
||||
|
@ -133,50 +146,10 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
|
|||
* Returns "DSA", indicating the Digital Signature Algorithm (DSA) as
|
||||
* defined by the Digital Signature Standard (DSS), FIPS 186.
|
||||
*/
|
||||
public String getName ()
|
||||
{ return "DSA"; }
|
||||
|
||||
|
||||
/*
|
||||
* For algorithm IDs which haven't been created from a DER encoded
|
||||
* value, "params" must be created.
|
||||
*/
|
||||
private void initializeParams () throws IOException {
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
out.putInteger(p);
|
||||
out.putInteger(q);
|
||||
out.putInteger(g);
|
||||
DerOutputStream result = new DerOutputStream();
|
||||
result.write(DerValue.tag_Sequence, out);
|
||||
encodedParams = result.toByteArray();
|
||||
public String getName() {
|
||||
return "DSA";
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses algorithm parameters P, Q, and G. They're found
|
||||
* in the "params" member, which never needs to be changed.
|
||||
*/
|
||||
protected void decodeParams () throws IOException {
|
||||
if (encodedParams == null) {
|
||||
throw new IOException("DSA alg params are null");
|
||||
}
|
||||
|
||||
DerValue params = new DerValue(encodedParams);
|
||||
if (params.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("DSA alg parsing error");
|
||||
}
|
||||
|
||||
params.data.reset ();
|
||||
|
||||
this.p = params.data.getBigInteger();
|
||||
this.q = params.data.getBigInteger();
|
||||
this.g = params.data.getBigInteger();
|
||||
|
||||
if (params.data.available () != 0)
|
||||
throw new IOException ("AlgIdDSA params, extra="+
|
||||
params.data.available ());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns a formatted string describing the parameters.
|
||||
*/
|
||||
|
@ -197,4 +170,44 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
|
|||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream. Override to check
|
||||
* on the 'p', 'q', 'g', and 'encodedParams'.
|
||||
*
|
||||
* @param stream the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
@java.io.Serial
|
||||
private void readObject(ObjectInputStream stream) throws IOException {
|
||||
try {
|
||||
stream.defaultReadObject();
|
||||
// if any of the 'p', 'q', 'g', 'encodedParams' is non-null,
|
||||
// then they must be all non-null w/ matching encoding
|
||||
if ((p != null || q != null || g != null || encodedParams != null)
|
||||
&& !Arrays.equals(encodedParams, encode(p, q, g))) {
|
||||
throw new InvalidObjectException("Invalid DSA alg params");
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the DER encoding w/ the specified 'p', 'q', 'g'
|
||||
*/
|
||||
private static byte[] encode(BigInteger p, BigInteger q,
|
||||
BigInteger g) throws IOException {
|
||||
if (p == null || q == null || g == null) {
|
||||
throw new InvalidObjectException("invalid null value");
|
||||
}
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
out.putInteger(p);
|
||||
out.putInteger(q);
|
||||
out.putInteger(g);
|
||||
DerOutputStream result = new DerOutputStream();
|
||||
result.write(DerValue.tag_Sequence, out);
|
||||
return result.toByteArray();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue