Skip to content
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

Sanitize boolean conversions in signature subpackets. #1575

Closed
44 changes: 44 additions & 0 deletions core/src/main/java/org/bouncycastle/util/Booleans.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.bouncycastle.util;

public class Booleans {

/**
* Convert the given boolean value into a one-entry byte array, where true is represented by a 1 and false is a 0.
* @param bool boolean value
* @return byte array
*/
public static byte[] toByteArray(boolean bool)
{
byte[] bytes = new byte[1];
if (bool)
{
bytes[0] = 1;
}
return bytes;
}

/**
* Convert a one-entry byte array into a boolean.
* If the byte array doesn't have one entry, or if this entry is neither a 0 nor 1, this method throws an
* {@link IllegalArgumentException}.
* A 1 is translated into true, a 0 into false.
* @param bytes byte array
* @return boolean
*/
public static boolean fromByteArray(byte[] bytes)
{
if (bytes.length != 1)
{
throw new IllegalArgumentException("Byte array has unexpected length. Expected length 1, got " + bytes.length);
}
if (bytes[0] == 0)
{
return false;
}
else if (bytes[0] == 1)
{
return true;
}
else throw new IllegalArgumentException("Unexpected byte value for boolean encoding: " + bytes[0]);
}
}
41 changes: 41 additions & 0 deletions core/src/test/java/org/bouncycastle/util/utiltest/BytesTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.bouncycastle.util.utiltest;

import junit.framework.TestCase;
import org.bouncycastle.util.Booleans;

public class BytesTest extends TestCase {

public void testParseFalse() {
byte[] bFalse = Booleans.toByteArray(false);
assertEquals(1, bFalse.length);
assertEquals(0, bFalse[0]);
assertFalse(Booleans.fromByteArray(bFalse));
}

public void testParseTrue() {
byte[] bTrue = Booleans.toByteArray(true);
assertEquals(1, bTrue.length);
assertEquals(1, bTrue[1]);
assertTrue(Booleans.fromByteArray(bTrue));
}

public void testParseTooShort() {
byte[] bTooShort = new byte[0];
try {
Booleans.fromByteArray(bTooShort);
fail("Should throw.");
} catch (IllegalArgumentException e) {
// expected.
}
}

public void testParseTooLong() {
byte[] bTooLong = new byte[42];
try {
Booleans.fromByteArray(bTooLong);
fail("Should throw.");
} catch (IllegalArgumentException e) {
// expected.
}
}
}
25 changes: 5 additions & 20 deletions pg/src/main/java/org/bouncycastle/bcpg/sig/Exportable.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,14 @@

import org.bouncycastle.bcpg.SignatureSubpacket;
import org.bouncycastle.bcpg.SignatureSubpacketTags;
import org.bouncycastle.util.Booleans;

/**
* packet giving signature creation time.
* Signature subpacket indicating, whether the carrying signature is intended to be exportable.
*/
public class Exportable
extends SignatureSubpacket
{
private static byte[] booleanToByteArray(
boolean value)
{
byte[] data = new byte[1];

if (value)
{
data[0] = 1;
return data;
}
else
{
return data;
}
}

{
public Exportable(
boolean critical,
boolean isLongLength,
Expand All @@ -37,11 +22,11 @@ public Exportable(
boolean critical,
boolean isExportable)
{
super(SignatureSubpacketTags.EXPORTABLE, critical, false, booleanToByteArray(isExportable));
super(SignatureSubpacketTags.EXPORTABLE, critical, false, Booleans.toByteArray(isExportable));
}

public boolean isExportable()
{
return data[0] != 0;
return Booleans.fromByteArray(data);
}
}
25 changes: 5 additions & 20 deletions pg/src/main/java/org/bouncycastle/bcpg/sig/PrimaryUserID.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,14 @@

import org.bouncycastle.bcpg.SignatureSubpacket;
import org.bouncycastle.bcpg.SignatureSubpacketTags;
import org.bouncycastle.util.Booleans;

/**
* packet giving whether or not the signature is signed using the primary user ID for the key.
* Signature Subpacket indicating, whether the signed User-ID is marked as the primary user ID for the key.
*/
public class PrimaryUserID
extends SignatureSubpacket
{
private static byte[] booleanToByteArray(
boolean value)
{
byte[] data = new byte[1];

if (value)
{
data[0] = 1;
return data;
}
else
{
return data;
}
}

{
public PrimaryUserID(
boolean critical,
boolean isLongLength,
Expand All @@ -37,11 +22,11 @@ public PrimaryUserID(
boolean critical,
boolean isPrimaryUserID)
{
super(SignatureSubpacketTags.PRIMARY_USER_ID, critical, false, booleanToByteArray(isPrimaryUserID));
super(SignatureSubpacketTags.PRIMARY_USER_ID, critical, false, Booleans.toByteArray(isPrimaryUserID));
}

public boolean isPrimaryUserID()
{
return data[0] != 0;
return Booleans.fromByteArray(data);
}
}
25 changes: 5 additions & 20 deletions pg/src/main/java/org/bouncycastle/bcpg/sig/Revocable.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,14 @@

import org.bouncycastle.bcpg.SignatureSubpacket;
import org.bouncycastle.bcpg.SignatureSubpacketTags;
import org.bouncycastle.util.Booleans;

/**
* packet giving whether or not is revocable.
* Signature subpacket indicating, whether the carrying signature can be revoked.
*/
public class Revocable
extends SignatureSubpacket
{
private static byte[] booleanToByteArray(
boolean value)
{
byte[] data = new byte[1];

if (value)
{
data[0] = 1;
return data;
}
else
{
return data;
}
}

{
public Revocable(
boolean critical,
boolean isLongLength,
Expand All @@ -37,11 +22,11 @@ public Revocable(
boolean critical,
boolean isRevocable)
{
super(SignatureSubpacketTags.REVOCABLE, critical, false, booleanToByteArray(isRevocable));
super(SignatureSubpacketTags.REVOCABLE, critical, false, Booleans.toByteArray(isRevocable));
}

public boolean isRevocable()
{
return data[0] != 0;
return Booleans.fromByteArray(data);
}
}