Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion ca/certificates.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,22 @@ func (rca *RootCA) IssueAndSaveNewCertificates(kw KeyWriter, cn, ou, org string)
return &tlsKeyPair, nil
}

// Normally we can just call cert.Verify(opts), but since we actually want more information about
// whether a certificate is not yet valid or expired, we also need to perform the expiry checks ourselves.
func verifyCertificate(cert *x509.Certificate, opts x509.VerifyOptions) error {
_, err := cert.Verify(opts)
if invalidErr, ok := err.(x509.CertificateInvalidError); ok && invalidErr.Reason == x509.Expired {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just want to confirm that x509.Expired is returned when NotBefore is violated as well as the NotAfter case.

Copy link
Copy Markdown
Contributor Author

@cyli cyli Feb 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

now := time.Now().UTC()
if now.Before(cert.NotBefore) {
return errors.Wrapf(err, "certificate not valid before %s, and it is currently %s",
cert.NotBefore.UTC().Format(time.RFC1123), now.Format(time.RFC1123))
}
return errors.Wrapf(err, "certificate expires at %s, and it is currently %s",
cert.NotAfter.UTC().Format(time.RFC1123), now.Format(time.RFC1123))
}
return err
}

// RequestAndSaveNewCertificates gets new certificates issued, either by signing them locally if a signer is
// available, or by requesting them from the remote server at remoteAddr.
func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, kw KeyWriter, config CertificateRequestConfig) (*tls.Certificate, error) {
Expand Down Expand Up @@ -199,7 +215,7 @@ func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, kw KeyWrit
Roots: rca.Pool,
}
// Check to see if this certificate was signed by our CA, and isn't expired
if _, err := X509Cert.Verify(opts); err != nil {
if err := verifyCertificate(X509Cert, opts); err != nil {
return nil, err
}

Expand Down
4 changes: 2 additions & 2 deletions ca/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ func GenerateJoinToken(rootCA *RootCA) string {

func getCAHashFromToken(token string) (digest.Digest, error) {
split := strings.Split(token, "-")
if len(split) != 4 || split[0] != "SWMTKN" || split[1] != "1" {
if len(split) != 4 || split[0] != "SWMTKN" || split[1] != "1" || len(split[2]) != base36DigestLen || len(split[3]) != maxGeneratedSecretLength {
return "", errors.New("invalid join token")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps not for this PR, but should we mention what it's expected to look like?

"token should start with SWMTKN, followed by a 36 character alphanumeric code"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether that may be too much information to give in an error message, just because the the swarm token is: SWMTKN-<version>-<other data>, and depending on what version the token is, the rest of the token may be different.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although at this point, there is only 1 version, so maybe we can deal with messaging other versions later :)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I wasn't sure either; also not if that should be done in swarmkit, or "prettied" in docker

}

Expand Down Expand Up @@ -273,7 +273,7 @@ func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter)
}

// Check to see if this certificate was signed by our CA, and isn't expired
if _, err := X509Cert.Verify(opts); err != nil {
if err := verifyCertificate(X509Cert, opts); err != nil {
return nil, err
}

Expand Down
13 changes: 9 additions & 4 deletions ca/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,14 @@ func TestDownloadRootCAWrongCAHash(t *testing.T) {
os.RemoveAll(tc.Paths.RootCA.Cert)

// invalid token
_, err := ca.DownloadRootCA(tc.Context, tc.Paths.RootCA, "invalidtoken", tc.ConnBroker)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid join token")
for _, invalid := range []string{
"invalidtoken", // completely invalid
"SWMTKN-1-3wkodtpeoipd1u1hi0ykdcdwhw16dk73ulqqtn14b3indz68rf-4myj5xihyto11dg1cn55w8p6", // mistyped
} {
_, err := ca.DownloadRootCA(tc.Context, tc.Paths.RootCA, invalid, tc.ConnBroker)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid join token")
}

// invalid hash token
splitToken := strings.Split(tc.ManagerToken, "-")
Expand All @@ -65,7 +70,7 @@ func TestDownloadRootCAWrongCAHash(t *testing.T) {

os.RemoveAll(tc.Paths.RootCA.Cert)

_, err = ca.DownloadRootCA(tc.Context, tc.Paths.RootCA, replacementToken, tc.ConnBroker)
_, err := ca.DownloadRootCA(tc.Context, tc.Paths.RootCA, replacementToken, tc.ConnBroker)
require.Error(t, err)
require.Contains(t, err.Error(), "remote CA does not match fingerprint.")
}
Expand Down