Alternative TLS implementation in Go
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

393 lignes
13 KiB

  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package tls
  5. // Delegated credentials for TLS
  6. // (https://tools.ietf.org/html/draft-ietf-tls-subcerts-02) is an IETF Internet
  7. // draft and proposed TLS extension. This allows a backend server to delegate
  8. // TLS termination to a trusted frontend. If the client supports this extension,
  9. // then the frontend may use a "delegated credential" as the signing key in the
  10. // handshake. A delegated credential is a short lived key pair delegated to the
  11. // server by an entity trusted by the client. Once issued, credentials can't be
  12. // revoked; in order to mitigate risk in case the frontend is compromised, the
  13. // credential is only valid for a short time (days, hours, or even minutes).
  14. //
  15. // This implements draft 02. This draft doesn't specify an object identifier for
  16. // the X.509 extension; we use one assigned by Cloudflare. In addition, IANA has
  17. // not assigned an extension ID for this extension; we picked up one that's not
  18. // yet taken.
  19. //
  20. // TODO(cjpatton) Only ECDSA is supported with delegated credentials for now;
  21. // we'd like to suppoort for EcDSA signatures once these have better support
  22. // upstream.
  23. import (
  24. "bytes"
  25. "crypto"
  26. "crypto/ecdsa"
  27. "crypto/elliptic"
  28. "crypto/x509"
  29. "encoding/asn1"
  30. "encoding/binary"
  31. "errors"
  32. "fmt"
  33. "time"
  34. )
  35. const (
  36. // length of the public key field
  37. dcPubKeyFieldLen = 3
  38. dcMaxTTLSeconds = 60 * 60 * 24 * 7 // 7 days
  39. dcMaxTTL = time.Duration(dcMaxTTLSeconds * time.Second)
  40. dcMaxPublicKeyLen = 1 << 24 // Bytes
  41. dcMaxSignatureLen = 1 << 16 // Bytes
  42. )
  43. var errNoDelegationUsage = errors.New("certificate not authorized for delegation")
  44. // delegationUsageId is the DelegationUsage X.509 extension OID
  45. //
  46. // NOTE(cjpatton) This OID is a child of Cloudflare's IANA-assigned OID.
  47. var delegationUsageId = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 44363, 44}
  48. // canDelegate returns true if a certificate can be used for delegated
  49. // credentials.
  50. func canDelegate(cert *x509.Certificate) bool {
  51. // Check that the digitalSignature key usage is set.
  52. if (cert.KeyUsage & x509.KeyUsageDigitalSignature) == 0 {
  53. return false
  54. }
  55. // Check that the certificate has the DelegationUsage extension and that
  56. // it's non-critical (per the spec).
  57. for _, extension := range cert.Extensions {
  58. if extension.Id.Equal(delegationUsageId) {
  59. return true
  60. }
  61. }
  62. return false
  63. }
  64. // credential stores the public components of a credential.
  65. type credential struct {
  66. // The serialized form of the credential.
  67. raw []byte
  68. // The amount of time for which the credential is valid. Specifically, the
  69. // the credential expires `ValidTime` seconds after the `notBefore` of the
  70. // delegation certificate. The delegator shall not issue delegated
  71. // credentials that are valid for more than 7 days from the current time.
  72. //
  73. // When this data structure is serialized, this value is converted to a
  74. // uint32 representing the duration in seconds.
  75. validTime time.Duration
  76. // The signature scheme associated with the delegated credential public key.
  77. expectedCertVerifyAlgorithm SignatureScheme
  78. // The version of TLS in which the credential will be used.
  79. expectedVersion uint16
  80. // The credential public key.
  81. publicKey crypto.PublicKey
  82. }
  83. // isExpired returns true if the credential has expired. The end of the validity
  84. // interval is defined as the delegator certificate's notBefore field (`start`)
  85. // plus ValidTime seconds. This function simply checks that the current time
  86. // (`now`) is before the end of the valdity interval.
  87. func (cred *credential) isExpired(start, now time.Time) bool {
  88. end := start.Add(cred.validTime)
  89. return !now.Before(end)
  90. }
  91. // invalidTTL returns true if the credential's validity period is longer than the
  92. // maximum permitted. This is defined by the certificate's notBefore field
  93. // (`start`) plus the ValidTime, minus the current time (`now`).
  94. func (cred *credential) invalidTTL(start, now time.Time) bool {
  95. return cred.validTime > (now.Sub(start) + dcMaxTTL).Round(time.Second)
  96. }
  97. // marshalSubjectPublicKeyInfo returns a DER encoded SubjectPublicKeyInfo structure
  98. // (as defined in the X.509 standard) for the credential.
  99. func (cred *credential) marshalSubjectPublicKeyInfo() ([]byte, error) {
  100. switch cred.expectedCertVerifyAlgorithm {
  101. case ECDSAWithP256AndSHA256,
  102. ECDSAWithP384AndSHA384,
  103. ECDSAWithP521AndSHA512:
  104. serializedPublicKey, err := x509.MarshalPKIXPublicKey(cred.publicKey)
  105. if err != nil {
  106. return nil, err
  107. }
  108. return serializedPublicKey, nil
  109. default:
  110. return nil, fmt.Errorf("unsupported signature scheme: 0x%04x", cred.expectedCertVerifyAlgorithm)
  111. }
  112. }
  113. // marshal encodes a credential in the wire format specified in
  114. // https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.
  115. func (cred *credential) marshal() ([]byte, error) {
  116. // The number of bytes comprising the DC parameters, which includes the
  117. // validity time (4 bytes), the signature scheme of the public key (2 bytes), and
  118. // the protocol version (2 bytes).
  119. paramsLen := 8
  120. // The first 4 bytes are the valid_time, scheme, and version fields.
  121. serialized := make([]byte, paramsLen+dcPubKeyFieldLen)
  122. binary.BigEndian.PutUint32(serialized, uint32(cred.validTime/time.Second))
  123. binary.BigEndian.PutUint16(serialized[4:], uint16(cred.expectedCertVerifyAlgorithm))
  124. binary.BigEndian.PutUint16(serialized[6:], cred.expectedVersion)
  125. // Encode the public key and assert that the encoding is no longer than 2^16
  126. // bytes (per the spec).
  127. serializedPublicKey, err := cred.marshalSubjectPublicKeyInfo()
  128. if err != nil {
  129. return nil, err
  130. }
  131. if len(serializedPublicKey) > dcMaxPublicKeyLen {
  132. return nil, errors.New("public key is too long")
  133. }
  134. // The next 3 bytes are the length of the public key field, which may be up
  135. // to 2^24 bytes long.
  136. putUint24(serialized[paramsLen:], len(serializedPublicKey))
  137. // The remaining bytes are the public key itself.
  138. serialized = append(serialized, serializedPublicKey...)
  139. cred.raw = serialized
  140. return serialized, nil
  141. }
  142. // unmarshalCredential decodes a credential and returns it.
  143. func unmarshalCredential(serialized []byte) (*credential, error) {
  144. // The number of bytes comprising the DC parameters.
  145. paramsLen := 8
  146. if len(serialized) < paramsLen+dcPubKeyFieldLen {
  147. return nil, errors.New("credential is too short")
  148. }
  149. // Parse the valid_time, scheme, and version fields.
  150. validTime := time.Duration(binary.BigEndian.Uint32(serialized)) * time.Second
  151. scheme := SignatureScheme(binary.BigEndian.Uint16(serialized[4:]))
  152. version := binary.BigEndian.Uint16(serialized[6:])
  153. // Parse the SubjectPublicKeyInfo.
  154. pk, err := x509.ParsePKIXPublicKey(serialized[paramsLen+dcPubKeyFieldLen:])
  155. if err != nil {
  156. return nil, err
  157. }
  158. if _, ok := pk.(*ecdsa.PublicKey); !ok {
  159. return nil, fmt.Errorf("unsupported delegation key type: %T", pk)
  160. }
  161. return &credential{
  162. raw: serialized,
  163. validTime: validTime,
  164. expectedCertVerifyAlgorithm: scheme,
  165. expectedVersion: version,
  166. publicKey: pk,
  167. }, nil
  168. }
  169. // getCredentialLen returns the number of bytes comprising the serialized
  170. // credential that starts at the beginning of the input slice. It returns an
  171. // error if the input is too short to contain a credential.
  172. func getCredentialLen(serialized []byte) (int, error) {
  173. paramsLen := 8
  174. if len(serialized) < paramsLen+dcPubKeyFieldLen {
  175. return 0, errors.New("credential is too short")
  176. }
  177. // First several bytes are the valid_time, scheme, and version fields.
  178. serialized = serialized[paramsLen:]
  179. // The next 3 bytes are the length of the serialized public key, which may
  180. // be up to 2^24 bytes in length.
  181. serializedPublicKeyLen := getUint24(serialized)
  182. serialized = serialized[dcPubKeyFieldLen:]
  183. if len(serialized) < serializedPublicKeyLen {
  184. return 0, errors.New("public key of credential is too short")
  185. }
  186. return paramsLen + dcPubKeyFieldLen + serializedPublicKeyLen, nil
  187. }
  188. // delegatedCredential stores a credential and its delegation.
  189. type delegatedCredential struct {
  190. raw []byte
  191. // The credential, which contains a public and its validity time.
  192. cred *credential
  193. // The signature scheme used to sign the credential.
  194. algorithm SignatureScheme
  195. // The credential's delegation.
  196. signature []byte
  197. }
  198. // ensureCertificateHasLeaf parses the leaf certificate if needed.
  199. func ensureCertificateHasLeaf(cert *Certificate) error {
  200. var err error
  201. if cert.Leaf == nil {
  202. if len(cert.Certificate[0]) == 0 {
  203. return errors.New("missing leaf certificate")
  204. }
  205. cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
  206. if err != nil {
  207. return err
  208. }
  209. }
  210. return nil
  211. }
  212. // validate checks that that the signature is valid, that the credential hasn't
  213. // expired, and that the TTL is valid. It also checks that certificate can be
  214. // used for delegation.
  215. func (dc *delegatedCredential) validate(cert *x509.Certificate, now time.Time) (bool, error) {
  216. // Check that the cert can delegate.
  217. if !canDelegate(cert) {
  218. return false, errNoDelegationUsage
  219. }
  220. if dc.cred.isExpired(cert.NotBefore, now) {
  221. return false, errors.New("credential has expired")
  222. }
  223. if dc.cred.invalidTTL(cert.NotBefore, now) {
  224. return false, errors.New("credential TTL is invalid")
  225. }
  226. // Prepare the credential for verification.
  227. rawCred, err := dc.cred.marshal()
  228. if err != nil {
  229. return false, err
  230. }
  231. hash := getHash(dc.algorithm)
  232. in := prepareDelegation(hash, rawCred, cert.Raw, dc.algorithm)
  233. // TODO(any) This code overlaps significantly with verifyHandshakeSignature()
  234. // in ../auth.go. This should be refactored.
  235. switch dc.algorithm {
  236. case ECDSAWithP256AndSHA256,
  237. ECDSAWithP384AndSHA384,
  238. ECDSAWithP521AndSHA512:
  239. pk, ok := cert.PublicKey.(*ecdsa.PublicKey)
  240. if !ok {
  241. return false, errors.New("expected ECDSA public key")
  242. }
  243. sig := new(ecdsaSignature)
  244. if _, err = asn1.Unmarshal(dc.signature, sig); err != nil {
  245. return false, err
  246. }
  247. return ecdsa.Verify(pk, in, sig.R, sig.S), nil
  248. default:
  249. return false, fmt.Errorf(
  250. "unsupported signature scheme: 0x%04x", dc.algorithm)
  251. }
  252. }
  253. // unmarshalDelegatedCredential decodes a DelegatedCredential structure.
  254. func unmarshalDelegatedCredential(serialized []byte) (*delegatedCredential, error) {
  255. // Get the length of the serialized credential that begins at the start of
  256. // the input slice.
  257. serializedCredentialLen, err := getCredentialLen(serialized)
  258. if err != nil {
  259. return nil, err
  260. }
  261. // Parse the credential.
  262. cred, err := unmarshalCredential(serialized[:serializedCredentialLen])
  263. if err != nil {
  264. return nil, err
  265. }
  266. // Parse the signature scheme.
  267. serialized = serialized[serializedCredentialLen:]
  268. if len(serialized) < 4 {
  269. return nil, errors.New("delegated credential is too short")
  270. }
  271. scheme := SignatureScheme(binary.BigEndian.Uint16(serialized))
  272. // Parse the signature length.
  273. serialized = serialized[2:]
  274. serializedSignatureLen := binary.BigEndian.Uint16(serialized)
  275. // Prase the signature.
  276. serialized = serialized[2:]
  277. if len(serialized) < int(serializedSignatureLen) {
  278. return nil, errors.New("signature of delegated credential is too short")
  279. }
  280. sig := serialized[:serializedSignatureLen]
  281. return &delegatedCredential{
  282. raw: serialized,
  283. cred: cred,
  284. algorithm: scheme,
  285. signature: sig,
  286. }, nil
  287. }
  288. // getCurve maps the SignatureScheme to its corresponding elliptic.Curve.
  289. func getCurve(scheme SignatureScheme) elliptic.Curve {
  290. switch scheme {
  291. case ECDSAWithP256AndSHA256:
  292. return elliptic.P256()
  293. case ECDSAWithP384AndSHA384:
  294. return elliptic.P384()
  295. case ECDSAWithP521AndSHA512:
  296. return elliptic.P521()
  297. default:
  298. return nil
  299. }
  300. }
  301. // getHash maps the SignatureScheme to its corresponding hash function.
  302. //
  303. // TODO(any) This function overlaps with hashForSignatureScheme in 13.go.
  304. func getHash(scheme SignatureScheme) crypto.Hash {
  305. switch scheme {
  306. case ECDSAWithP256AndSHA256:
  307. return crypto.SHA256
  308. case ECDSAWithP384AndSHA384:
  309. return crypto.SHA384
  310. case ECDSAWithP521AndSHA512:
  311. return crypto.SHA512
  312. default:
  313. return 0 // Unknown hash function
  314. }
  315. }
  316. // prepareDelegation returns a hash of the message that the delegator is to
  317. // sign. The inputs are the credential (`cred`), the DER-encoded delegator
  318. // certificate (`delegatorCert`) and the signature scheme of the delegator
  319. // (`delegatorAlgorithm`).
  320. func prepareDelegation(hash crypto.Hash, cred, delegatorCert []byte, delegatorAlgorithm SignatureScheme) []byte {
  321. h := hash.New()
  322. // The header.
  323. h.Write(bytes.Repeat([]byte{0x20}, 64))
  324. h.Write([]byte("TLS, server delegated credentials"))
  325. h.Write([]byte{0x00})
  326. // The delegation certificate.
  327. h.Write(delegatorCert)
  328. // The credential.
  329. h.Write(cred)
  330. // The delegator signature scheme.
  331. var serializedScheme [2]byte
  332. binary.BigEndian.PutUint16(serializedScheme[:], uint16(delegatorAlgorithm))
  333. h.Write(serializedScheme[:])
  334. return h.Sum(nil)
  335. }