Alternative TLS implementation in Go
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

393 Zeilen
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. }