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.

JGitPublicKeyAuthentication.java 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. * Copyright (C) 2018, 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.internal.transport.sshd;
  11. import java.io.IOException;
  12. import java.security.PublicKey;
  13. import java.util.HashSet;
  14. import java.util.LinkedList;
  15. import java.util.List;
  16. import java.util.Set;
  17. import org.apache.sshd.client.auth.pubkey.UserAuthPublicKey;
  18. import org.apache.sshd.client.session.ClientSession;
  19. import org.apache.sshd.common.NamedFactory;
  20. import org.apache.sshd.common.RuntimeSshException;
  21. import org.apache.sshd.common.SshConstants;
  22. import org.apache.sshd.common.config.keys.KeyUtils;
  23. import org.apache.sshd.common.signature.Signature;
  24. import org.apache.sshd.common.signature.SignatureFactoriesHolder;
  25. import org.apache.sshd.common.util.buffer.Buffer;
  26. /**
  27. * Custom {@link UserAuthPublicKey} implementation fixing SSHD-1105: if there
  28. * are several signature algorithms applicable for a public key type, we must
  29. * try them all, in the correct order.
  30. *
  31. * @see <a href="https://issues.apache.org/jira/browse/SSHD-1105">SSHD-1105</a>
  32. * @see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=572056">Bug
  33. * 572056</a>
  34. */
  35. public class JGitPublicKeyAuthentication extends UserAuthPublicKey {
  36. private final List<String> algorithms = new LinkedList<>();
  37. JGitPublicKeyAuthentication(List<NamedFactory<Signature>> factories) {
  38. super(factories);
  39. }
  40. @Override
  41. protected boolean sendAuthDataRequest(ClientSession session, String service)
  42. throws Exception {
  43. if (current == null) {
  44. algorithms.clear();
  45. }
  46. String currentAlgorithm = null;
  47. if (current != null && !algorithms.isEmpty()) {
  48. currentAlgorithm = algorithms.remove(0);
  49. }
  50. if (currentAlgorithm == null) {
  51. try {
  52. if (keys == null || !keys.hasNext()) {
  53. if (log.isDebugEnabled()) {
  54. log.debug(
  55. "sendAuthDataRequest({})[{}] no more keys to send", //$NON-NLS-1$
  56. session, service);
  57. }
  58. return false;
  59. }
  60. current = keys.next();
  61. algorithms.clear();
  62. } catch (Error e) { // Copied from superclass
  63. warn("sendAuthDataRequest({})[{}] failed ({}) to get next key: {}", //$NON-NLS-1$
  64. session, service, e.getClass().getSimpleName(),
  65. e.getMessage(), e);
  66. throw new RuntimeSshException(e);
  67. }
  68. }
  69. PublicKey key;
  70. try {
  71. key = current.getPublicKey();
  72. } catch (Error e) { // Copied from superclass
  73. warn("sendAuthDataRequest({})[{}] failed ({}) to retrieve public key: {}", //$NON-NLS-1$
  74. session, service, e.getClass().getSimpleName(),
  75. e.getMessage(), e);
  76. throw new RuntimeSshException(e);
  77. }
  78. if (currentAlgorithm == null) {
  79. String keyType = KeyUtils.getKeyType(key);
  80. Set<String> aliases = new HashSet<>(
  81. KeyUtils.getAllEquivalentKeyTypes(keyType));
  82. aliases.add(keyType);
  83. List<NamedFactory<Signature>> existingFactories;
  84. if (current instanceof SignatureFactoriesHolder) {
  85. existingFactories = ((SignatureFactoriesHolder) current)
  86. .getSignatureFactories();
  87. } else {
  88. existingFactories = getSignatureFactories();
  89. }
  90. if (existingFactories != null) {
  91. // Select the factories by name and in order
  92. existingFactories.forEach(f -> {
  93. if (aliases.contains(f.getName())) {
  94. algorithms.add(f.getName());
  95. }
  96. });
  97. }
  98. currentAlgorithm = algorithms.isEmpty() ? keyType
  99. : algorithms.remove(0);
  100. }
  101. String name = getName();
  102. if (log.isDebugEnabled()) {
  103. log.debug(
  104. "sendAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_REQUEST request {} type={} - fingerprint={}", //$NON-NLS-1$
  105. session, service, name, currentAlgorithm,
  106. KeyUtils.getFingerPrint(key));
  107. }
  108. Buffer buffer = session
  109. .createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST);
  110. buffer.putString(session.getUsername());
  111. buffer.putString(service);
  112. buffer.putString(name);
  113. buffer.putBoolean(false);
  114. buffer.putString(currentAlgorithm);
  115. buffer.putPublicKey(key);
  116. session.writePacket(buffer);
  117. return true;
  118. }
  119. @Override
  120. protected void releaseKeys() throws IOException {
  121. algorithms.clear();
  122. current = null;
  123. super.releaseKeys();
  124. }
  125. }