You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PushCertificateParserTest.java 6.3KB

Rewrite push certificate parsing - Consistently return structured data, such as actual ReceiveCommands, which is more useful for callers that are doing things other than verifying the signature, e.g. recording the set of commands. - Store the certificate version field, as this is required to be part of the signed payload. - Add a toText() method to recreate the actual payload for signature verification. This requires keeping track of the un-chomped command strings from the original protocol stream. - Separate the parser from the certificate itself, so the actual PushCertificate object can be immutable. Make a fair attempt at deep immutability, but this is not possible with the current mutable ReceiveCommand structure. - Use more detailed error messages that don't involve NON-NLS strings. - Document null return values more thoroughly. Instead of having the undocumented behavior of throwing NPE from certain methods if they are not first guarded by enabled(), eliminate enabled() and return null from those methods. - Add tests for parsing a push cert from a section of pkt-line stream using a real live stream captured with Wireshark (which, it should be noted, uncovered several simply incorrect statements in C git's Documentation/technical/pack-protocol.txt). This is a slightly breaking API change to classes that were technically public and technically released in 4.0. However, it is highly unlikely that people were actually depending on public behavior, since there were no public methods to create PushCertificates with anything other than null field values, or a PushCertificateParser that did anything other than infinite loop or throw exceptions when reading. Change-Id: I5382193347a8eb1811032d9b32af9651871372d0
9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. * Copyright (C) 2015, Google Inc.
  3. *
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Distribution License v1.0 which
  6. * accompanies this distribution, is reproduced below, and is
  7. * available at http://www.eclipse.org/org/documents/edl-v10.php
  8. *
  9. * All rights reserved.
  10. *
  11. * Redistribution and use in source and binary forms, with or
  12. * without modification, are permitted provided that the following
  13. * conditions are met:
  14. *
  15. * - Redistributions of source code must retain the above copyright
  16. * notice, this list of conditions and the following disclaimer.
  17. *
  18. * - Redistributions in binary form must reproduce the above
  19. * copyright notice, this list of conditions and the following
  20. * disclaimer in the documentation and/or other materials provided
  21. * with the distribution.
  22. *
  23. * - Neither the name of the Eclipse Foundation, Inc. nor the
  24. * names of its contributors may be used to endorse or promote
  25. * products derived from this software without specific prior
  26. * written permission.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  29. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  30. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  31. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  32. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  33. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  34. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  35. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  36. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  37. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  38. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  39. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  40. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  41. */
  42. package org.eclipse.jgit.transport;
  43. import static org.junit.Assert.assertEquals;
  44. import static org.junit.Assert.assertFalse;
  45. import static org.junit.Assert.assertNotEquals;
  46. import java.io.ByteArrayInputStream;
  47. import java.io.EOFException;
  48. import java.io.IOException;
  49. import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
  50. import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
  51. import org.eclipse.jgit.lib.Config;
  52. import org.eclipse.jgit.lib.Constants;
  53. import org.eclipse.jgit.lib.ObjectId;
  54. import org.eclipse.jgit.lib.Repository;
  55. import org.eclipse.jgit.transport.BaseReceivePack.ReceiveConfig;
  56. import org.junit.Test;
  57. /** Test for push certificate parsing. */
  58. public class PushCertificateParserTest {
  59. @Test
  60. public void parseCertFromPktLine() throws Exception {
  61. // Example push certificate generated by C git 2.2.0.
  62. String input = "001ccertificate version 0.1\n"
  63. + "0041pusher Dave Borowitz <dborowitz@google.com> 1433954361 -0700\n"
  64. + "0024pushee git://localhost/repo.git\n"
  65. + "002anonce 1433954361-bde756572d665bba81d8\n"
  66. + "0005\n"
  67. + "00680000000000000000000000000000000000000000"
  68. + " 6c2b981a177396fb47345b7df3e4d3f854c6bea7"
  69. + " refs/heads/master\n"
  70. + "0022-----BEGIN PGP SIGNATURE-----\n"
  71. + "0016Version: GnuPG v1\n"
  72. + "0005\n"
  73. + "0045iQEcBAABAgAGBQJVeGg5AAoJEPfTicJkUdPkUggH/RKAeI9/i/LduuiqrL/SSdIa\n"
  74. + "00459tYaSqJKLbXz63M/AW4Sp+4u+dVCQvnAt/a35CVEnpZz6hN4Kn/tiswOWVJf4CO7\n"
  75. + "0045htNubGs5ZMwvD6sLYqKAnrM3WxV/2TbbjzjZW6Jkidz3jz/WRT4SmjGYiEO7aA+V\n"
  76. + "00454ZdIS9f7sW5VsHHYlNThCA7vH8Uu48bUovFXyQlPTX0pToSgrWV3JnTxDNxfn3iG\n"
  77. + "0045IL0zTY/qwVCdXgFownLcs6J050xrrBWIKqfcWr3u4D2aCLyR0v+S/KArr7ulZygY\n"
  78. + "0045+SOklImn8TAZiNxhWtA6ens66IiammUkZYFv7SSzoPLFZT4dC84SmGPWgf94NoQ=\n"
  79. + "000a=XFeC\n"
  80. + "0020-----END PGP SIGNATURE-----\n"
  81. + "0012push-cert-end\n";
  82. PacketLineIn pckIn = newPacketLineIn(input);
  83. Config cfg = new Config();
  84. cfg.setString("receive", null, "certnonceseed", "sekret");
  85. Repository db = new InMemoryRepository(
  86. new DfsRepositoryDescription("repo"));
  87. PushCertificateParser parser = new PushCertificateParser(
  88. db, new ReceiveConfig(cfg));
  89. parser.receiveHeader(pckIn, false);
  90. parser.addCommand(pckIn.readStringRaw());
  91. assertEquals(PushCertificateParser.BEGIN_SIGNATURE, pckIn.readStringRaw());
  92. parser.receiveSignature(pckIn);
  93. PushCertificate cert = parser.build();
  94. assertEquals("0.1", cert.getVersion());
  95. assertEquals("Dave Borowitz", cert.getPusherIdent().getName());
  96. assertEquals("dborowitz@google.com",
  97. cert.getPusherIdent().getEmailAddress());
  98. assertEquals(1433954361000L, cert.getPusherIdent().getWhen().getTime());
  99. assertEquals(-7 * 60, cert.getPusherIdent().getTimeZoneOffset());
  100. assertEquals("git://localhost/repo.git", cert.getPushee());
  101. assertEquals("1433954361-bde756572d665bba81d8", cert.getNonce());
  102. assertNotEquals(cert.getNonce(), parser.getAdvertiseNonce());
  103. assertEquals(PushCertificate.NonceStatus.BAD, cert.getNonceStatus());
  104. assertEquals(1, cert.getCommands().size());
  105. ReceiveCommand cmd = cert.getCommands().get(0);
  106. assertEquals("refs/heads/master", cmd.getRefName());
  107. assertEquals(ObjectId.zeroId(), cmd.getOldId());
  108. assertEquals("6c2b981a177396fb47345b7df3e4d3f854c6bea7",
  109. cmd.getNewId().name());
  110. assertEquals(concatPacketLines(input, 0, 6), cert.toText());
  111. String signature = concatPacketLines(input, 7, 16);
  112. assertFalse(signature.contains(PushCertificateParser.BEGIN_SIGNATURE));
  113. assertFalse(signature.contains(PushCertificateParser.END_SIGNATURE));
  114. assertEquals(signature, cert.getSignature());
  115. }
  116. @Test
  117. public void testConcatPacketLines() throws Exception {
  118. String input = "000bline 1\n000bline 2\n000bline 3\n";
  119. assertEquals("line 1\n", concatPacketLines(input, 0, 1));
  120. assertEquals("line 1\nline 2\n", concatPacketLines(input, 0, 2));
  121. assertEquals("line 2\nline 3\n", concatPacketLines(input, 1, 3));
  122. assertEquals("line 2\nline 3\n", concatPacketLines(input, 1, 4));
  123. }
  124. private static String concatPacketLines(String input, int begin, int end)
  125. throws IOException {
  126. StringBuilder result = new StringBuilder();
  127. int i = 0;
  128. PacketLineIn pckIn = newPacketLineIn(input);
  129. while (i < end) {
  130. String line;
  131. try {
  132. line = pckIn.readStringRaw();
  133. } catch (EOFException e) {
  134. break;
  135. }
  136. if (++i > begin) {
  137. result.append(line);
  138. }
  139. }
  140. return result.toString();
  141. }
  142. private static PacketLineIn newPacketLineIn(String input) {
  143. return new PacketLineIn(new ByteArrayInputStream(Constants.encode(input)));
  144. }
  145. }