errorEncodingFromFile=Error encoding from file {0}
errorInBase64CodeReadingStream=Error in Base64 code reading stream.
errorInPackedRefs=error in packed-refs
+errorInvalidPushCert=error: invalid protocol: {0}
errorInvalidProtocolWantedOldNewRef=error: invalid protocol: wanted 'old new ref'
errorListing=Error listing {0}
errorOccurredDuringUnpackingOnTheRemoteEnd=error occurred during unpacking on the remote end: {0}
/***/ public String errorEncodingFromFile;
/***/ public String errorInBase64CodeReadingStream;
/***/ public String errorInPackedRefs;
+ /***/ public String errorInvalidPushCert;
/***/ public String errorInvalidProtocolWantedOldNewRef;
/***/ public String errorListing;
/***/ public String errorOccurredDuringUnpackingOnTheRemoteEnd;
/** The size of the received pack, including index size */
private Long packSize;
+ PushCertificateParser pushCertificateParser;
+
+ /**
+ * @return the push certificate used to verify the pushers identity.
+ */
+ PushCertificate getPushCertificate() {
+ return pushCertificateParser;
+ }
+
/**
* Create a new pack receive for an open repository.
*
refFilter = RefFilter.DEFAULT;
advertisedHaves = new HashSet<ObjectId>();
clientShallowCommits = new HashSet<ObjectId>();
+ pushCertificateParser = new PushCertificateParser(db, cfg);
}
/** Configuration for receive operations. */
final boolean allowNonFastForwards;
final boolean allowOfsDelta;
+ final String certNonceSeed;
+ final int certNonceSlopLimit;
+
ReceiveConfig(final Config config) {
checkReceivedObjects = config.getBoolean(
"receive", "fsckobjects", //$NON-NLS-1$ //$NON-NLS-2$
"denynonfastforwards", false); //$NON-NLS-1$
allowOfsDelta = config.getBoolean("repack", "usedeltabaseoffset", //$NON-NLS-1$ //$NON-NLS-2$
true);
+ certNonceSeed = config.getString("receive", null, "certnonceseed"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ certNonceSlopLimit = config.getInt("receive", "certnonceslop", 0); //$NON-NLS-1$ //$NON-NLS-2$
}
ObjectChecker newObjectChecker() {
adv.advertiseCapability(CAPABILITY_SIDE_BAND_64K);
adv.advertiseCapability(CAPABILITY_DELETE_REFS);
adv.advertiseCapability(CAPABILITY_REPORT_STATUS);
+ if (pushCertificateParser.enabled())
+ adv.advertiseCapability(
+ pushCertificateParser.getAdvertiseNonce());
if (db.getRefDatabase().performsAtomicTransactions())
adv.advertiseCapability(CAPABILITY_ATOMIC);
if (allowOfsDelta)
final FirstLine firstLine = new FirstLine(line);
enabledCapabilities = firstLine.getCapabilities();
line = firstLine.getLine();
+
+ if (line.equals(GitProtocolConstants.OPTION_PUSH_CERT))
+ pushCertificateParser.receiveHeader(pckIn,
+ !isBiDirectionalPipe());
}
+ if (line.equals("-----BEGIN PGP SIGNATURE-----\n")) //$NON-NLS-1$
+ pushCertificateParser.receiveSignature(pckIn);
+
+ if (pushCertificateParser.enabled())
+ pushCertificateParser.addCommand(line);
+
if (line.length() < 83) {
final String m = JGitText.get().errorInvalidProtocolWantedOldNewRef;
sendError(m);
*/
public static final String OPTION_SYMREF = "symref"; //$NON-NLS-1$
+ /**
+ * The client will send a push certificate.
+ *
+ * @since 3.7
+ */
+ public static final String OPTION_PUSH_CERT = "push-cert"; //$NON-NLS-1$
+
/**
* The client supports atomic pushes. If this option is used, the server
* will update all refs within one atomic transaction.
*/
public static final String CAPABILITY_SIDE_BAND_64K = "side-band-64k"; //$NON-NLS-1$
+ /**
+ * The server allows recording of push certificates.
+ *
+ * @since 3.7
+ */
+ public static final String CAPABILITY_PUSH_CERT = "push-cert"; //$NON-NLS-1$
+
static enum MultiAck {
OFF, CONTINUE, DETAILED;
}
--- /dev/null
+/*
+ * Copyright (C) 2015, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.transport;
+
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.eclipse.jgit.internal.storage.dfs.DfsRepository;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.NonceGenerator;
+import org.eclipse.jgit.transport.PushCertificate.NonceStatus;
+
+/**
+ * The nonce generator which was first introduced to git-core.
+ */
+public class HMACSHA1NonceGenerator implements NonceGenerator {
+
+ private Mac mac;
+
+ /**
+ * @param seed
+ * @throws IllegalStateException
+ */
+ public HMACSHA1NonceGenerator(String seed) throws IllegalStateException {
+ try {
+ byte[] keyBytes = seed.getBytes("ISO-8859-1"); //$NON-NLS-1$
+ SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA1"); //$NON-NLS-1$
+ mac = Mac.getInstance("HmacSHA1"); //$NON-NLS-1$
+ mac.init(signingKey);
+ } catch (InvalidKeyException e) {
+ throw new IllegalStateException(e);
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException(e);
+ } catch (UnsupportedEncodingException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public synchronized String createNonce(Repository repo, long timestamp)
+ throws IllegalStateException {
+ String path;
+ if (repo instanceof DfsRepository)
+ path = ((DfsRepository) repo).getDescription().getRepositoryName();
+ else if (repo.getDirectory() != null)
+ path = repo.getDirectory().getPath();
+ else
+ throw new IllegalStateException();
+
+ String input = path + ":" + String.valueOf(timestamp); //$NON-NLS-1$
+ byte[] rawHmac;
+ try {
+ rawHmac = mac.doFinal(input.getBytes("UTF-8")); //$NON-NLS-1$
+ } catch (UnsupportedEncodingException e) {
+ throw new IllegalStateException(e);
+ }
+ String sentNonce = String.format(
+ "%d-%20X", new Long(timestamp), rawHmac); //$NON-NLS-1$
+ return sentNonce;
+ }
+
+ @Override
+ public NonceStatus verify(String received, String sent,
+ Repository db, boolean allowSlop, int slop) {
+ if (received.isEmpty())
+ return NonceStatus.MISSING;
+ else if (sent.isEmpty())
+ return NonceStatus.UNSOLICITED;
+ else if (received.equals(sent))
+ return NonceStatus.OK;
+
+ if (!allowSlop)
+ return NonceStatus.BAD;
+
+ /* nonce is concat(<seconds-since-epoch>, "-", <hmac>) */
+ int idxSent = sent.indexOf('-');
+ int idxRecv = received.indexOf('-');
+ if (idxSent == -1 || idxRecv == -1)
+ return NonceStatus.BAD;
+
+ long signedStamp;
+ long advertisedStamp;
+ try {
+ signedStamp = Long.parseLong(received.substring(0, idxRecv));
+ advertisedStamp = Long.parseLong(sent.substring(0, idxSent));
+ } catch (Exception e) {
+ return NonceStatus.BAD;
+ }
+
+ // what we would have signed earlier
+ String expect = createNonce(db, signedStamp);
+
+ if (!expect.equals(received))
+ return NonceStatus.BAD;
+
+ long nonceStampSlop = Math.abs(advertisedStamp - signedStamp);
+
+ if (nonceStampSlop <= slop) {
+ return NonceStatus.OK;
+ } else {
+ return NonceStatus.SLOP;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2015, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.transport;
+
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.PushCertificate.NonceStatus;
+
+/**
+ * A NonceGenerator is used to create a nonce to be sent out to the pusher who
+ * will sign the nonce to prove it is not a replay attack on the push
+ * certificate.
+ */
+public interface NonceGenerator {
+
+ /**
+ * @param db
+ * The repository which should be used to obtain a unique String
+ * such that the pusher cannot forge nonces by pushing to another
+ * repository at the same time as well and reusing the nonce.
+ * @param timestamp
+ * The current time in seconds.
+ * @return The nonce to be signed by the pusher
+ * @throws IllegalStateException
+ */
+ public String createNonce(Repository db, long timestamp)
+ throws IllegalStateException;
+
+ /**
+ * @param received
+ * The nonce which was received from the server
+ * @param sent
+ * The nonce which was originally sent out to the client.
+ * @param db
+ * The repository which should be used to obtain a unique String
+ * such that the pusher cannot forge nonces by pushing to another
+ * repository at the same time as well and reusing the nonce.
+ *
+ * @param allowSlop
+ * If the receiving backend is is able to generate slop. This is
+ * the case for serving via http protocol using more than one
+ * http frontend. The client would talk to different http
+ * frontends, which may have a slight difference of time due to
+ * @param slop
+ * If `allowSlop` is true, this specifies the number of seconds
+ * which we allow as slop.
+ *
+ * @return a NonceStatus indicating the trustworthiness of the received
+ * nonce.
+ */
+ public NonceStatus verify(String received, String sent,
+ Repository db, boolean allowSlop, int slop);
+}
--- /dev/null
+/*
+ * Copyright (C) 2015, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+/**
+ * The required information to verify the push.
+ */
+public class PushCertificate {
+
+ /** The tuple "name <email>" as presented in the push certificate */
+ String pusher;
+
+ /** The remote URL the signed push goes to */
+ String pushee;
+
+ /** What we think about the returned signed nonce */
+ NonceStatus nonceStatus;
+
+ /**
+ *
+ *
+ */
+ public enum NonceStatus {
+ /**
+ *
+ */
+ UNSOLICITED,
+ /**
+ *
+ */
+ BAD,
+ /**
+ *
+ */
+ MISSING,
+ /**
+ *
+ */
+ OK,
+ /**
+ *
+ */
+ SLOP
+ }
+
+ /**
+ *
+ */
+ String commandList;
+
+ /**
+ *
+ */
+ String signature;
+
+ /**
+ *
+ * @return the signature, consisting of the lines received between the lines
+ * '----BEGIN GPG SIGNATURE-----\n' and the '----END GPG
+ * SIGNATURE-----\n'
+ */
+ public String getSignature() {
+ return signature;
+ }
+
+ /**
+ * @return the list of commands as one string to be feed into the signature
+ * verifier.
+ */
+ public String getCommandList() {
+ return commandList;
+ }
+
+ /**
+ * @return the pushedCertPusher
+ */
+ public String getPusher() {
+ return pusher;
+ }
+
+ /**
+ * @return the pushedCertPushee
+ */
+ public String getPushee() {
+ return pushee;
+ }
+
+ /**
+ * @return the pushCertNonceStatus
+ */
+ public NonceStatus getNonceStatus() {
+ return nonceStatus;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2015, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.transport;
+
+import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_PUSH_CERT;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.BaseReceivePack.ReceiveConfig;
+
+/**
+ * @author sbeller
+ *
+ */
+public class PushCertificateParser extends PushCertificate {
+
+ private static final String VERSION = "version "; //$NON-NLS-1$
+
+ private static final String PUSHER = "pusher"; //$NON-NLS-1$
+
+ private static final String PUSHEE = "pushee"; //$NON-NLS-1$
+
+ private static final String NONCE = "nonce"; //$NON-NLS-1$
+
+ /** The individual certificate which is presented to the client */
+ private String sentNonce;
+
+ /**
+ * The nonce the pusher signed. This may vary from pushCertNonce See
+ * git-core documentation for reasons.
+ */
+ private String receivedNonce;
+
+ /**
+ * The maximum time difference which is acceptable between advertised nonce
+ * and received signed nonce.
+ */
+ private int nonceSlopLimit;
+
+ NonceGenerator nonceGenerator;
+
+ /**
+ * used to build up commandlist
+ */
+ StringBuilder commandlistBuilder;
+
+ /** Database we write the push certificate into. */
+ private Repository db;
+
+ PushCertificateParser(Repository into, ReceiveConfig cfg) {
+ nonceSlopLimit = cfg.certNonceSlopLimit;
+ nonceGenerator = cfg.certNonceSeed != null
+ ? new HMACSHA1NonceGenerator(cfg.certNonceSeed)
+ : null;
+ db = into;
+ }
+
+ /**
+ * @return if the server is configured to use signed pushes.
+ */
+ public boolean enabled() {
+ return nonceGenerator != null;
+ }
+
+ /**
+ * @return the whole string for the nonce to be included into the capability
+ * advertisement.
+ */
+ public String getAdvertiseNonce() {
+ sentNonce = nonceGenerator.createNonce(db,
+ TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()));
+ return CAPABILITY_PUSH_CERT + "=" + sentNonce; //$NON-NLS-1$
+ }
+
+ private String parseNextLine(PacketLineIn pckIn, String startingWith)
+ throws IOException {
+ String s = pckIn.readString();
+ if (!s.startsWith(startingWith))
+ throw new IOException(MessageFormat.format(
+ JGitText.get().errorInvalidPushCert,
+ "expected " + startingWith)); //$NON-NLS-1$
+ return s.substring(startingWith.length());
+ }
+
+ /**
+ * Receive a list of commands from the input encapsulated in a push
+ * certificate. This method doesn't deal with the first line "push-cert \NUL
+ * <capabilities>", but assumes the first line including the capabilities
+ * has already been dealt with.
+ *
+ * @param pckIn
+ * where we take the push certificate header from.
+ * @param stateless
+ * If this server is run as a stateless server, such that it
+ * cannot store the sent push certificate and needs to validate
+ * what the client sends back.
+ *
+ * @throws IOException
+ */
+ public void receiveHeader(PacketLineIn pckIn, boolean stateless)
+ throws IOException {
+ try {
+ String version = parseNextLine(pckIn, VERSION);
+ if (!version.equals("0.1")) { //$NON-NLS-1$
+ throw new IOException(MessageFormat.format(
+ JGitText.get().errorInvalidPushCert,
+ "version not supported")); //$NON-NLS-1$
+ }
+ pusher = parseNextLine(pckIn, PUSHER);
+ pushee = parseNextLine(pckIn, PUSHEE);
+ receivedNonce = parseNextLine(pckIn, NONCE);
+ // an empty line
+ if (pckIn.readString() != "") { //$NON-NLS-1$
+ throw new IOException(MessageFormat.format(
+ JGitText.get().errorInvalidPushCert,
+ "expected empty line after header")); //$NON-NLS-1$
+ }
+ } catch (EOFException eof) {
+ throw new IOException(MessageFormat.format(
+ JGitText.get().errorInvalidPushCert,
+ "broken push certificate header")); //$NON-NLS-1$
+ }
+ nonceStatus = nonceGenerator.verify(receivedNonce, sentNonce, db,
+ stateless, nonceSlopLimit);
+ }
+
+ /**
+ * Reads the gpg signature. This method assumes the line "-----BEGIN PGP
+ * SIGNATURE-----\n" has already been parsed and continues parsing until an
+ * "-----END PGP SIGNATURE-----\n" is found.
+ *
+ * @param pckIn
+ * where we read the signature from.
+ * @throws IOException
+ */
+ public void receiveSignature(PacketLineIn pckIn) throws IOException {
+ try {
+ StringBuilder sig = new StringBuilder();
+ String line = pckIn.readStringRaw();
+ while (!line.equals("-----END PGP SIGNATURE-----\n")) //$NON-NLS-1$
+ sig.append(line);
+ signature = sig.toString();
+ commandList = commandlistBuilder.toString();
+ } catch (EOFException eof) {
+ throw new IOException(MessageFormat.format(
+ JGitText.get().errorInvalidPushCert,
+ "broken push certificate signature")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * @param rawLine
+ */
+ public void addCommand(String rawLine) {
+ commandlistBuilder.append(rawLine);
+ }
+}