Skip to content

Commit 95622b3

Browse files
committed
Ensure we can transfer SecretBytes via remoting
If we tried to transfer SecretBytes via Remoting then the remote side would end up with the encrypted byte[] but not the key needed to decrypt the data. Sending the decryption key would be a bad thing, but we can send the data in plain text to the agent and then re-encrypt it with the remoting (agent) sides key. As generally the remoting side would not be a Jenkins the mock encryption key would be used in this case. Whilst the mock key is static, it is not expected that ian agent persists these SecretBytes. fixes: #1013
1 parent 6afd2a4 commit 95622b3

File tree

1 file changed

+29
-1
lines changed

1 file changed

+29
-1
lines changed

src/main/java/com/cloudbees/plugins/credentials/SecretBytes.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@
3535
import edu.umd.cs.findbugs.annotations.CheckForNull;
3636
import edu.umd.cs.findbugs.annotations.NonNull;
3737
import hudson.Util;
38+
import hudson.remoting.Channel;
3839
import hudson.util.Secret;
40+
import java.io.ObjectStreamException;
3941
import java.io.Serializable;
4042
import java.security.GeneralSecurityException;
4143
import java.util.Arrays;
@@ -78,7 +80,8 @@ public class SecretBytes implements Serializable {
7880
*/
7981
private static final Logger LOGGER = Logger.getLogger(SecretBytes.class.getName());
8082
/**
81-
* The encrypted bytes.
83+
* The (usually) encrypted bytes.
84+
* Will be in plain text during remoting calls.
8285
*/
8386
@NonNull
8487
private final byte[] value;
@@ -119,6 +122,14 @@ private SecretBytes(boolean encrypted, @NonNull byte[] value) {
119122
}
120123
}
121124

125+
/**
126+
* Construct a SecretBytes with the specified value (that may or may not be encrypted) that is used raw without any transformation.
127+
* @param value explicit value to use for the data. No encryption or dencryption is performed on this value and it is used as is.
128+
*/
129+
private SecretBytes(@NonNull byte[] value) {
130+
this.value = value;
131+
}
132+
122133
/**
123134
* Returns the raw unencrypted data. The caller is responsible for zeroing out the returned {@code byte[]} after
124135
* use.
@@ -343,6 +354,23 @@ public static String toString(SecretBytes s) {
343354
return s == null ? "" : s.toString();
344355
}
345356

357+
protected Object writeReplace() throws ObjectStreamException {
358+
if (Channel.current() == null) {
359+
return this;
360+
}
361+
// we need plain text during remoting serialisation as the remote side will not have the confidential key
362+
return new SecretBytes(this.getPlainData());
363+
}
364+
365+
protected Object readResolve() throws ObjectStreamException {
366+
if (Channel.current() == null) {
367+
return this;
368+
}
369+
// re-encrypt the byte array after serialisation.
370+
// The remote side may have its own confidential key (for Jenkins to Jenkins remoting, or will use the mock key for an agent)
371+
return SecretBytes.fromRawBytes(value);
372+
}
373+
346374
/**
347375
* Our XStream converter.
348376
*/

0 commit comments

Comments
 (0)