Skip to content

Commit 98547fd

Browse files
committed
throw parsing exceptions when DER data is invalid, and handle empty element at the end of the sequence
1 parent 2a83aa1 commit 98547fd

File tree

3 files changed

+58
-43
lines changed

3 files changed

+58
-43
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/CertUtils.java

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@
106106
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
107107
import com.oracle.graal.python.nodes.ErrorMessages;
108108
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
109-
import com.oracle.graal.python.util.BiConsumer;
110109
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
111110
import com.oracle.truffle.api.TruffleFile;
112111
import com.oracle.truffle.api.nodes.Node;
@@ -151,7 +150,7 @@ static boolean isCrl(boolean[] keyUsage) {
151150
* _ssl.c#_decode_certificate
152151
*/
153152
@TruffleBoundary
154-
public static PDict decodeCertificate(Node node, X509Certificate cert) throws IOException, CertificateParsingException {
153+
public static PDict decodeCertificate(Node node, X509Certificate cert) throws CertificateParsingException {
155154
PythonObjectFactory factory = PythonObjectFactory.getUncached();
156155
PDict dict = factory.createDict();
157156
HashingStorage storage = dict.getDictStorage();
@@ -289,77 +288,92 @@ private static final class DerValue {
289288
private static final byte OBJECT_IDENTIFIER = 0x06;
290289
private static final byte SEQUENCE = 0x10;
291290

291+
private static final String ERROR_MESSAGE = "Invalid DER encoded data";
292+
292293
final byte[] data;
293-
final int end;
294294
final boolean isContextTag;
295295
final int contentLen;
296296
final int contentStart;
297297
int contentTag;
298298

299-
DerValue(byte[] data) {
299+
DerValue(byte[] data) throws CertificateParsingException {
300300
this(data, 0, data.length);
301301
}
302302

303-
DerValue(byte[] data, int offset, int end) {
304-
this.data = data;
305-
this.end = end;
306-
307-
this.contentTag = data[offset] & 0b11111;
308-
this.isContextTag = (data[offset] & 0b11000000) == 0b10000000;
309-
int[] lenAndOffset = readLength(data, offset);
310-
this.contentStart = lenAndOffset[0];
311-
this.contentLen = lenAndOffset[1];
312-
313-
assert this.contentTag != 0b11111 : "extended tag range not supported";
314-
assert contentStart + contentLen <= end;
303+
DerValue(byte[] data, int offset, int end) throws CertificateParsingException {
304+
if (offset == data.length) {
305+
// this is a 0-length value at the end of the data
306+
this.data = data;
307+
this.contentTag = 0;
308+
this.isContextTag = false;
309+
this.contentStart = offset;
310+
this.contentLen = 0;
311+
} else if (offset < data.length) {
312+
this.data = data;
313+
314+
this.contentTag = data[offset] & 0b11111;
315+
this.isContextTag = (data[offset] & 0b11000000) == 0b10000000;
316+
int[] lenAndOffset = readLength(data, offset);
317+
this.contentStart = lenAndOffset[0];
318+
this.contentLen = lenAndOffset[1];
319+
320+
assert this.contentTag != 0b11111 : "extended tag range not supported";
321+
assert contentStart + contentLen <= end;
322+
} else {
323+
throw new CertificateParsingException(ERROR_MESSAGE);
324+
}
315325
}
316326

317-
private static int[] readLength(byte[] data, int offset) {
318-
int lenBase = data[offset + 1] & 0xff;
319-
if (lenBase < 128) {
320-
return new int[]{offset + 2, lenBase};
321-
} else {
322-
int lengthOfLength = lenBase - 128;
323-
if (lengthOfLength > 4) {
324-
throw new IllegalArgumentException("longer than int-range DER values not supported");
325-
}
326-
int fullLength = 0;
327-
for (int i = 0; i < lengthOfLength; i++) {
328-
fullLength = (fullLength << 8) | data[offset + 2 + i];
327+
private static int[] readLength(byte[] data, int offset) throws CertificateParsingException {
328+
try {
329+
int lenBase = data[offset + 1] & 0xff;
330+
if (lenBase < 128) {
331+
return new int[]{offset + 2, lenBase};
332+
} else {
333+
int lengthOfLength = lenBase - 128;
334+
if (lengthOfLength > 4) {
335+
throw new IllegalArgumentException("longer than int-range DER values not supported");
336+
}
337+
int fullLength = 0;
338+
for (int i = 0; i < lengthOfLength; i++) {
339+
fullLength = (fullLength << 8) | data[offset + 2 + i];
340+
}
341+
return new int[]{offset + 2 + lengthOfLength, fullLength};
329342
}
330-
return new int[]{offset + 2 + lengthOfLength, fullLength};
343+
} catch (ArrayIndexOutOfBoundsException e) {
344+
throw new CertificateParsingException(ERROR_MESSAGE);
331345
}
332346
}
333347

334348
byte[] getRawData() {
335349
return Arrays.copyOfRange(data, contentStart, contentStart + contentLen);
336350
}
337351

338-
DerValue getObjectIdentifier() {
352+
DerValue getObjectIdentifier() throws CertificateParsingException {
339353
if (contentTag != OBJECT_IDENTIFIER) {
340354
return null;
341355
} else {
342356
return new DerValue(data, contentStart, contentStart + contentLen);
343357
}
344358
}
345359

346-
DerValue getContextTag(int tag) {
360+
DerValue getContextTag(int tag) throws CertificateParsingException {
347361
if (contentTag != tag || !isContextTag) {
348362
return null;
349363
} else {
350364
return new DerValue(data, contentStart, contentStart + contentLen);
351365
}
352366
}
353367

354-
DerValue getOctetString() {
368+
DerValue getOctetString() throws CertificateParsingException {
355369
if (contentTag != OCTET_STRING) {
356370
return null;
357371
} else {
358372
return new DerValue(data, contentStart, contentStart + contentLen);
359373
}
360374
}
361375

362-
DerValue getSequence() {
376+
DerValue getSequence() throws CertificateParsingException {
363377
if (contentTag != SEQUENCE) {
364378
return null;
365379
} else {
@@ -386,15 +400,20 @@ String getGeneralNameURI() {
386400
}
387401
}
388402

389-
List<DerValue> getSequenceElements() {
403+
List<DerValue> getSequenceElements() throws CertificateParsingException {
390404
List<DerValue> result = new ArrayList<>();
391405
iterateSequence((e, r) -> {
392406
result.add(e);
393407
}, result);
394408
return result;
395409
}
396410

397-
<T> void iterateSequence(BiConsumer<DerValue, T> consumer, T value) {
411+
@FunctionalInterface
412+
private interface DerSequenceConsumer<A, B> {
413+
abstract void accept(A a, B b) throws CertificateParsingException;
414+
}
415+
416+
<T> void iterateSequence(DerSequenceConsumer<DerValue, T> consumer, T value) throws CertificateParsingException {
398417
int sequenceStart = contentStart;
399418
int sequenceEnd = contentStart + contentLen;
400419
DerValue sequenceData = getSequence();
@@ -411,7 +430,7 @@ <T> void iterateSequence(BiConsumer<DerValue, T> consumer, T value) {
411430
}
412431

413432
@TruffleBoundary
414-
private static PTuple parseCRLPoints(X509Certificate cert, PythonObjectFactory factory) throws IOException {
433+
private static PTuple parseCRLPoints(X509Certificate cert, PythonObjectFactory factory) throws CertificateParsingException {
415434
List<String> result = new ArrayList<>();
416435
byte[] bytes = cert.getExtensionValue(OID_CRL_DISTRIBUTION_POINTS);
417436
if (bytes == null) {
@@ -452,7 +471,7 @@ private static PTuple parseCRLPoints(X509Certificate cert, PythonObjectFactory f
452471
}
453472

454473
@TruffleBoundary
455-
private static PTuple parseCAIssuers(X509Certificate cert, PythonObjectFactory factory) throws IOException {
474+
private static PTuple parseCAIssuers(X509Certificate cert, PythonObjectFactory factory) throws CertificateParsingException {
456475
List<String> result = new ArrayList<>();
457476
byte[] bytes = cert.getExtensionValue(OID_AUTHORITY_INFO_ACCESS);
458477
if (bytes == null) {
@@ -484,7 +503,7 @@ private static PTuple parseCAIssuers(X509Certificate cert, PythonObjectFactory f
484503
}
485504

486505
@TruffleBoundary
487-
private static PTuple parseOCSP(X509Certificate cert, PythonObjectFactory factory) {
506+
private static PTuple parseOCSP(X509Certificate cert, PythonObjectFactory factory) throws CertificateParsingException {
488507
List<String> result = new ArrayList<>();
489508
byte[] bytes = cert.getExtensionValue(OID_AUTHORITY_INFO_ACCESS);
490509
if (bytes == null) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,7 @@ Object getCerts(PSSLContext self, @SuppressWarnings("unused") boolean binary_for
982982
}
983983
}
984984
return factory().createList(result.toArray(new Object[result.size()]));
985-
} catch (KeyStoreException | NoSuchAlgorithmException | IOException | CertificateParsingException ex) {
985+
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateParsingException ex) {
986986
throw PRaiseSSLErrorNode.raiseUncached(this, SSLErrorCode.ERROR_SSL, ex);
987987
}
988988
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLSocketBuiltins.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,8 @@
4141
package com.oracle.graal.python.builtins.objects.ssl;
4242

4343
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.NotImplementedError;
44-
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SSLError;
4544
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError;
4645

47-
import java.io.IOException;
4846
import java.nio.ByteBuffer;
4947
import java.security.cert.Certificate;
5048
import java.security.cert.CertificateEncodingException;
@@ -320,8 +318,6 @@ PDict getPeerCertDict(PSSLSocket self, @SuppressWarnings("unused") boolean der)
320318
return CertUtils.decodeCertificate(this, (X509Certificate) certificate);
321319
} catch (CertificateParsingException e) {
322320
return factory().createDict();
323-
} catch (IOException ex) {
324-
throw raise(SSLError, ex);
325321
}
326322
}
327323
return factory().createDict();

0 commit comments

Comments
 (0)