Skip to content

Commit 085b4b1

Browse files
author
drighetto
committed
Add support for HS2019
1 parent 487ab38 commit 085b4b1

File tree

3 files changed

+89
-29
lines changed

3 files changed

+89
-29
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
<dependency>
4040
<groupId>org.tomitribe</groupId>
4141
<artifactId>tomitribe-http-signatures</artifactId>
42-
<version>1.3</version>
42+
<version>1.8</version>
4343
</dependency>
4444
<!-- https://mvnrepository.com/artifact/net.portswigger.burp.extender/burp-extender-api -->
4545
<dependency>

src/main/java/burp/ConfigSettings.java

Lines changed: 73 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import javax.swing.*;
44
import javax.swing.event.ChangeEvent;
55
import java.awt.*;
6+
import java.awt.event.ItemEvent;
7+
import java.awt.event.ItemListener;
68
import java.awt.event.MouseAdapter;
79
import java.awt.event.MouseEvent;
810
import java.io.IOException;
@@ -13,6 +15,7 @@
1315
import static burp.Signing.log;
1416

1517
public class ConfigSettings {
18+
public static String SIGNATURE_ALGORITHM = "rsa-sha256";
1619
public LinkedHashMap<String, String> settings; // key is e.g. "Header", value is "Authorization"
1720
// profiles: key is the name of the Tab, value is a settings LinkedHashMap
1821
private LinkedHashMap<String, LinkedHashMap<String, String>> profiles;
@@ -23,6 +26,8 @@ public class ConfigSettings {
2326
JCheckBox checkBoxToolScanner = new JCheckBox("Scanner");
2427
JCheckBox checkBoxToolIntruder = new JCheckBox("Intruder");
2528
JCheckBox checkBoxToolRepeater = new JCheckBox("Repeater");
29+
JCheckBox useHS2019Signature = new JCheckBox("HS2019");
30+
JCheckBox useRSASHA256Signature = new JCheckBox("RSA-SHA256");
2631
private boolean tabChangeListenerLock = false;
2732

2833
ConfigSettings() {
@@ -83,7 +88,8 @@ public class ConfigSettings {
8388

8489
/**
8590
* Return the Burp frame used for the option dialog and the menu button
86-
* @return The Burp Suite frame
91+
*
92+
* @return The Burp Suite frame
8793
*/
8894
static JFrame getBurpFrame() {
8995
for (Frame f : Frame.getFrames()) {
@@ -96,8 +102,9 @@ static JFrame getBurpFrame() {
96102

97103
/**
98104
* Get the value from a key/profile setting (e.g. "keyId") from the active profile
99-
* @param key The key to retrieve
100-
* @return The value for the key belonging to the active profile
105+
*
106+
* @param key The key to retrieve
107+
* @return The value for the key belonging to the active profile
101108
*/
102109
public String getString(String key) {
103110
return profiles.get("ActiveKey").get(key);
@@ -117,6 +124,41 @@ protected void showSettings() {
117124
titleGlobalConfig.setForeground(Color.ORANGE);
118125
titleGlobalConfig.setFont(titleGlobalConfig.getFont().deriveFont(Font.BOLD, titleGlobalConfig.getFont().getSize() + 4));
119126
globalPanel.add(titleGlobalConfig);
127+
//Signature algo
128+
JLabel labelSignatureAlgo = new JLabel("Signature algorithm:");
129+
Font labelSigFont = labelSignatureAlgo.getFont();
130+
labelSignatureAlgo.setFont(labelSigFont.deriveFont(labelSigFont.getStyle() | Font.BOLD)); // make text bold
131+
globalPanel.add(labelSignatureAlgo);
132+
if ((Signing.callbacks.loadExtensionSetting("useHS2019Signature") != null) &&
133+
Signing.callbacks.loadExtensionSetting("useHS2019Signature").equals("true")) {
134+
useHS2019Signature.setSelected(true);
135+
useRSASHA256Signature.setSelected(false);
136+
ConfigSettings.SIGNATURE_ALGORITHM = "hs2019";
137+
} else {
138+
useHS2019Signature.setSelected(false);
139+
useRSASHA256Signature.setSelected(true);
140+
ConfigSettings.SIGNATURE_ALGORITHM = "rsa-sha256";
141+
}
142+
useHS2019Signature.addItemListener(new ItemListener() {
143+
@Override
144+
public void itemStateChanged(ItemEvent e) {
145+
if(e.getStateChange() == ItemEvent.SELECTED){
146+
ConfigSettings.this.useRSASHA256Signature.setSelected(false);
147+
ConfigSettings.SIGNATURE_ALGORITHM = "hs2019";
148+
}
149+
}
150+
});
151+
useRSASHA256Signature.addItemListener(new ItemListener() {
152+
@Override
153+
public void itemStateChanged(ItemEvent e) {
154+
if(e.getStateChange() == ItemEvent.SELECTED){
155+
ConfigSettings.this.useHS2019Signature.setSelected(false);
156+
ConfigSettings.SIGNATURE_ALGORITHM = "rsa-sha256";
157+
}
158+
}
159+
});
160+
globalPanel.add(useHS2019Signature);
161+
globalPanel.add(useRSASHA256Signature);
120162
// Checkboxes to enable/disable the extension for each Burp Suite tool
121163
JLabel labelTools = new JLabel("Enable the extension for the following Burp Suite tools:");
122164
Font labelToolsFont = labelTools.getFont();
@@ -173,7 +215,8 @@ public void mouseClicked(MouseEvent e) {
173215
// the user clicks on the label
174216
try {
175217
Desktop.getDesktop().browse(new URI("https://github.com/nccgroup/HTTPSignatures"));
176-
} catch (IOException | URISyntaxException e1) {}
218+
} catch (IOException | URISyntaxException e1) {
219+
}
177220
}
178221

179222
@Override
@@ -248,11 +291,12 @@ public void mouseExited(MouseEvent e) {
248291

249292
/**
250293
* Make a ProfileTab active
251-
* @param profileTab The ProfileTab to set active
294+
*
295+
* @param profileTab The ProfileTab to set active
252296
*/
253297
private void setActiveProfile(ProfileTab profileTab) {
254298
String tabName = profileTab.profileTabHandle.tabNameField.getText();
255-
tabName.replaceAll(";",""); // remove semicolons
299+
tabName.replaceAll(";", ""); // remove semicolons
256300
log("Setting active profile to '" + tabName + "' active");
257301

258302
LinkedHashMap<String, Object> newProfile = profileTab.getNewProfile();
@@ -265,7 +309,7 @@ private void setActiveProfile(ProfileTab profileTab) {
265309
}
266310
Object val = newProfile.get(key);
267311
String valStr = ((JTextField) val).getText();
268-
profileValues += valStr.replaceAll(";",""); // remove semicolons
312+
profileValues += valStr.replaceAll(";", ""); // remove semicolons
269313
newProfile2.put(key, valStr);
270314
log("Setting active profile " + tabName + ": key: " + key + " value: " + valStr);
271315
}
@@ -299,7 +343,7 @@ private void saveProfiles() {
299343
}
300344
LinkedHashMap<String, Object> newProfile = profileTab.getNewProfile();
301345
String tabName = profileTab.profileTabHandle.tabNameField.getText();
302-
tabName = tabName.replaceAll(";",""); // remove semicolons
346+
tabName = tabName.replaceAll(";", ""); // remove semicolons
303347

304348
if (!tabNames.isEmpty()) {
305349
// add semicolon, but not on first key
@@ -316,7 +360,7 @@ private void saveProfiles() {
316360
}
317361
Object val = newProfile.get(key);
318362
String valStr = ((JTextField) val).getText();
319-
valStr = valStr.replaceAll(";",""); // remove any semicolon
363+
valStr = valStr.replaceAll(";", ""); // remove any semicolon
320364
profileValues += valStr;
321365
log("Saving profile " + tabName + ": key: " + key + " value: " + valStr);
322366
}
@@ -359,6 +403,11 @@ private void saveProfiles() {
359403
Signing.DEBUG = false;
360404
Signing.callbacks.saveExtensionSetting("debug", "false");
361405
}
406+
if (useHS2019Signature.isSelected() || !useRSASHA256Signature.isSelected() || (!useRSASHA256Signature.isSelected() && !useHS2019Signature.isSelected())) {
407+
Signing.callbacks.saveExtensionSetting("useHS2019Signature", "true");
408+
} else {
409+
Signing.callbacks.saveExtensionSetting("useHS2019Signature", "false");
410+
}
362411
}
363412

364413
/**
@@ -374,7 +423,8 @@ private void addTab() {
374423

375424
/**
376425
* Add a new (empty) tab
377-
* @param tabName the name of the new tab
426+
*
427+
* @param tabName the name of the new tab
378428
*/
379429
private void addTab(String tabName) {
380430
tabChangeListenerLock = true;
@@ -387,9 +437,10 @@ private void addTab(String tabName) {
387437

388438
/**
389439
* Add a new tab with content
390-
* @param tabName The name of the new tab
391-
* @param tabConfig The configuration of the new tab (values separated by semicolons)
392-
* @param active Boolean: true means the profile is active; false means the profile is not active
440+
*
441+
* @param tabName The name of the new tab
442+
* @param tabConfig The configuration of the new tab (values separated by semicolons)
443+
* @param active Boolean: true means the profile is active; false means the profile is not active
393444
*/
394445
private void addTab(String tabName, String tabConfig, Boolean active) {
395446
tabChangeListenerLock = true;
@@ -416,8 +467,9 @@ private void addTab(String tabName, String tabConfig, Boolean active) {
416467

417468
/**
418469
* Checks if a color is bright or dark.
419-
* @param color The RGB color
420-
* @return True if bright, false if dark
470+
*
471+
* @param color The RGB color
472+
* @return True if bright, false if dark
421473
*/
422474
private boolean isColorBright(int color) {
423475
if (brightness(color) > 0.5) {
@@ -431,8 +483,9 @@ private boolean isColorBright(int color) {
431483
* Returns the brightness of a color.
432484
* Based on
433485
* https://chromium.googlesource.com/android_tools/+/18728e9dd5dd66d4f5edf1b792e77e2b544a1cb0/sdk/sources/android-19/android/graphics/Color.java#187
434-
* @param color The RGB color
435-
* @return A value between 0.0f and 1.0f
486+
*
487+
* @param color The RGB color
488+
* @return A value between 0.0f and 1.0f
436489
*/
437490
private float brightness(int color) {
438491
int r = (color >> 16) & 0xFF;
@@ -445,7 +498,8 @@ private float brightness(int color) {
445498

446499
/**
447500
* Close a tab
448-
* @param configTabContent The tab to close
501+
*
502+
* @param configTabContent The tab to close
449503
*/
450504
public void closeTab(JPanel configTabContent) {
451505
tabChangeListenerLock = true;
@@ -505,7 +559,7 @@ private void initTabs() {
505559
continue;
506560
}
507561
String tabName = profileTab.profileTabHandle.tabNameField.getText();
508-
if (tabName.equals(activeTabName) ) {
562+
if (tabName.equals(activeTabName)) {
509563
tabbedPane.setSelectedIndex(tabNum);
510564
}
511565
}

src/main/java/burp/Signing.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
import org.apache.http.client.methods.*;
55
import org.apache.http.entity.ByteArrayEntity;
66
import org.apache.http.entity.StringEntity;
7-
import org.tomitribe.auth.signatures.MissingRequiredHeaderException;
8-
import org.tomitribe.auth.signatures.PEM;
9-
import org.tomitribe.auth.signatures.Signature;
10-
import org.tomitribe.auth.signatures.Signer;
7+
import org.tomitribe.auth.signatures.*;
118

129
import java.io.ByteArrayOutputStream;
1310
import java.io.IOException;
@@ -21,10 +18,14 @@
2118
import java.security.MessageDigest;
2219
import java.security.NoSuchAlgorithmException;
2320
import java.security.PrivateKey;
21+
import java.security.spec.AlgorithmParameterSpec;
2422
import java.security.spec.InvalidKeySpecException;
23+
import java.security.spec.MGF1ParameterSpec;
24+
import java.security.spec.PSSParameterSpec;
2525
import java.text.Format;
2626
import java.text.SimpleDateFormat;
2727
import java.util.*;
28+
import java.util.Base64;
2829
import java.util.stream.Collectors;
2930

3031
public class Signing {
@@ -285,7 +286,7 @@ private static PrivateKey loadPrivateKey(String privateKeyFilename) {
285286
*/
286287
public static class RequestSigner {
287288
private static final SimpleDateFormat DATE_FORMAT;
288-
private static final String SIGNATURE_ALGORITHM = "rsa-sha256";
289+
private static final String SIGNATURE_ALGORITHM = ConfigSettings.SIGNATURE_ALGORITHM.trim();
289290
private Map<String, List<String>> REQUIRED_HEADERS;
290291

291292
static {
@@ -338,8 +339,13 @@ private List stringToList(String input_string) {
338339
* @return Signer
339340
*/
340341
protected Signer buildSigner(String apiKey, Key privateKey, String method) {
341-
final Signature signature = new Signature(
342-
apiKey, SIGNATURE_ALGORITHM, null, REQUIRED_HEADERS.get(method.toLowerCase()));
342+
Signature signature;
343+
if ("hs2019".equalsIgnoreCase(SIGNATURE_ALGORITHM)) {
344+
AlgorithmParameterSpec spec = new PSSParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512, 32, 1);
345+
signature = new Signature(apiKey, SigningAlgorithm.HS2019, Algorithm.RSA_PSS, spec, null, REQUIRED_HEADERS.get(method.toLowerCase()));
346+
} else {
347+
signature = new Signature(apiKey, SIGNATURE_ALGORITHM, null, REQUIRED_HEADERS.get(method.toLowerCase()));
348+
}
343349
return new Signer(privateKey, signature);
344350
}
345351

@@ -409,7 +415,7 @@ public void signRequest(HttpRequestBase request, String header_name) {
409415

410416
final Map<String, String> headers = extractHeadersToSign(request);
411417
String signature = this.calculateSignature(method, path, headers);
412-
//log("DEBUG: signed signature: " + signature);
418+
log("[DOM] Generated signature: " + signature);
413419

414420
if (header_name.equalsIgnoreCase("Signature") && signature.startsWith("Signature ")) {
415421
// remove "Signature" from the beginning of the string as we use "Signature" as the header name
@@ -451,7 +457,7 @@ private Map<String, String> extractHeadersToSign(HttpRequestBase request) {
451457
}
452458
return headersToSign.stream()
453459
// (request-target) is a pseudo-header
454-
.filter(header -> !header.toLowerCase().equals("(request-target)"))
460+
.filter(header -> !header.toLowerCase().equals("(request-target)") && !header.toLowerCase().equals("(created)"))
455461
.collect(Collectors.toMap(
456462
header -> header,
457463
header -> {

0 commit comments

Comments
 (0)