| OLD | NEW |
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // Package machinetoken implements generation of LUCI machine tokens. | 5 // Package machinetoken implements generation of LUCI machine tokens. |
| 6 package machinetoken | 6 package machinetoken |
| 7 | 7 |
| 8 import ( | 8 import ( |
| 9 "crypto/x509" | 9 "crypto/x509" |
| 10 "encoding/base64" | 10 "encoding/base64" |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 // Validate checks that token minting parameters are allowed. | 64 // Validate checks that token minting parameters are allowed. |
| 65 func (p *MintParams) Validate() error { | 65 func (p *MintParams) Validate() error { |
| 66 // Check FDQN. | 66 // Check FDQN. |
| 67 if p.FQDN != strings.ToLower(p.FQDN) { | 67 if p.FQDN != strings.ToLower(p.FQDN) { |
| 68 return fmt.Errorf("expecting FQDN in lowercase, got %q", p.FQDN) | 68 return fmt.Errorf("expecting FQDN in lowercase, got %q", p.FQDN) |
| 69 } | 69 } |
| 70 chunks := strings.SplitN(p.FQDN, ".", 2) | 70 chunks := strings.SplitN(p.FQDN, ".", 2) |
| 71 if len(chunks) != 2 { | 71 if len(chunks) != 2 { |
| 72 return fmt.Errorf("not a valid FQDN %q", p.FQDN) | 72 return fmt.Errorf("not a valid FQDN %q", p.FQDN) |
| 73 } | 73 } |
| 74 » host, domain := chunks[0], chunks[1] | 74 » domain := chunks[1] // e.g. "us-central1-a.c.project-id.internal" |
| 75 » if strings.ContainsRune(host, '@') { | |
| 76 » » return fmt.Errorf("forbidden character '@' in hostname %q", host
) | |
| 77 » } | |
| 78 | 75 |
| 79 // Check DomainConfig for given domain. | 76 // Check DomainConfig for given domain. |
| 80 domainCfg := domainConfig(p.Config, domain) | 77 domainCfg := domainConfig(p.Config, domain) |
| 81 if domainCfg == nil { | 78 if domainCfg == nil { |
| 82 return fmt.Errorf("the domain %q is not whitelisted in the confi
g", domain) | 79 return fmt.Errorf("the domain %q is not whitelisted in the confi
g", domain) |
| 83 } | 80 } |
| 84 if domainCfg.MachineTokenLifetime <= 0 { | 81 if domainCfg.MachineTokenLifetime <= 0 { |
| 85 return fmt.Errorf("machine tokens for machines in domain %q are
not allowed", domain) | 82 return fmt.Errorf("machine tokens for machines in domain %q are
not allowed", domain) |
| 86 } | 83 } |
| 87 | 84 |
| 88 // Make sure cert serial number fits into uint64. We don't support negat
ive or | 85 // Make sure cert serial number fits into uint64. We don't support negat
ive or |
| 89 // giant SNs. | 86 // giant SNs. |
| 90 sn := p.Cert.SerialNumber | 87 sn := p.Cert.SerialNumber |
| 91 if sn.Sign() <= 0 || sn.Cmp(maxUint64) >= 0 { | 88 if sn.Sign() <= 0 || sn.Cmp(maxUint64) >= 0 { |
| 92 return fmt.Errorf("invalid certificate serial number: %s", sn) | 89 return fmt.Errorf("invalid certificate serial number: %s", sn) |
| 93 } | 90 } |
| 94 return nil | 91 return nil |
| 95 } | 92 } |
| 96 | 93 |
| 97 // domainConfig returns DomainConfig for a domain. | 94 // domainConfig returns DomainConfig (part of *.cfg file) for a given domain. |
| 98 // | 95 // |
| 99 // Returns nil if there's no such config. | 96 // It enumerates all domains specified in the config finding first domain that |
| 97 // is equal to 'domain' or has it as a subdomain. |
| 98 // |
| 99 // Returns nil if requested domain is not represented in the config. |
| 100 func domainConfig(cfg *admin.CertificateAuthorityConfig, domain string) *admin.D
omainConfig { | 100 func domainConfig(cfg *admin.CertificateAuthorityConfig, domain string) *admin.D
omainConfig { |
| 101 for _, domainCfg := range cfg.KnownDomains { | 101 for _, domainCfg := range cfg.KnownDomains { |
| 102 for _, domainInCfg := range domainCfg.Domain { | 102 for _, domainInCfg := range domainCfg.Domain { |
| 103 » » » if domainInCfg == domain { | 103 » » » if domainInCfg == domain || strings.HasSuffix(domain, ".
"+domainInCfg) { |
| 104 return domainCfg | 104 return domainCfg |
| 105 } | 105 } |
| 106 } | 106 } |
| 107 } | 107 } |
| 108 return nil | 108 return nil |
| 109 } | 109 } |
| 110 | 110 |
| 111 // Mint generates a new machine token proto, signs and serializes it. | 111 // Mint generates a new machine token proto, signs and serializes it. |
| 112 // | 112 // |
| 113 // Returns its body as a proto, and as a signed base64-encoded final token. | 113 // Returns its body as a proto, and as a signed base64-encoded final token. |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 Lifespan: func(b proto.Message) tokensigning.Lifespan { | 187 Lifespan: func(b proto.Message) tokensigning.Lifespan { |
| 188 body := b.(*tokenserver.MachineTokenBody) | 188 body := b.(*tokenserver.MachineTokenBody) |
| 189 return tokensigning.Lifespan{ | 189 return tokensigning.Lifespan{ |
| 190 NotBefore: time.Unix(int64(body.IssuedAt), 0), | 190 NotBefore: time.Unix(int64(body.IssuedAt), 0), |
| 191 NotAfter: time.Unix(int64(body.IssuedAt)+int64(
body.Lifetime), 0), | 191 NotAfter: time.Unix(int64(body.IssuedAt)+int64(
body.Lifetime), 0), |
| 192 } | 192 } |
| 193 }, | 193 }, |
| 194 } | 194 } |
| 195 return i.InspectToken(c, tok) | 195 return i.InspectToken(c, tok) |
| 196 } | 196 } |
| OLD | NEW |