2018-06-13 23:20:56 +00:00
package acme
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/subtle"
"crypto/tls"
"encoding/asn1"
"testing"
2018-09-15 17:16:35 +00:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2018-06-13 23:20:56 +00:00
)
func TestTLSALPNChallenge ( t * testing . T ) {
domain := "localhost:23457"
2018-09-15 17:16:35 +00:00
2018-06-13 23:20:56 +00:00
mockValidate := func ( _ * jws , _ , _ string , chlng challenge ) error {
conn , err := tls . Dial ( "tcp" , domain , & tls . Config {
InsecureSkipVerify : true ,
} )
2018-09-15 17:16:35 +00:00
assert . NoError ( t , err , "Expected to connect to challenge server without an error" )
2018-06-13 23:20:56 +00:00
// Expect the server to only return one certificate
connState := conn . ConnectionState ( )
2018-09-15 17:16:35 +00:00
assert . Len ( t , connState . PeerCertificates , 1 , "Expected the challenge server to return exactly one certificate" )
2018-06-13 23:20:56 +00:00
remoteCert := connState . PeerCertificates [ 0 ]
2018-09-15 17:16:35 +00:00
assert . Len ( t , remoteCert . DNSNames , 1 , "Expected the challenge certificate to have exactly one DNSNames entry" )
assert . Equal ( t , domain , remoteCert . DNSNames [ 0 ] , "challenge certificate DNSName " )
assert . NotEmpty ( t , remoteCert . Extensions , "Expected the challenge certificate to contain extensions" )
2018-06-13 23:20:56 +00:00
idx := - 1
for i , ext := range remoteCert . Extensions {
if idPeAcmeIdentifierV1 . Equal ( ext . Id ) {
idx = i
break
}
}
2018-09-15 17:16:35 +00:00
require . NotEqual ( t , - 1 , idx , "Expected the challenge certificate to contain an extension with the id-pe-acmeIdentifier id," )
2018-06-13 23:20:56 +00:00
ext := remoteCert . Extensions [ idx ]
2018-09-15 17:16:35 +00:00
assert . True ( t , ext . Critical , "Expected the challenge certificate id-pe-acmeIdentifier extension to be marked as critical" )
2018-06-13 23:20:56 +00:00
zBytes := sha256 . Sum256 ( [ ] byte ( chlng . KeyAuthorization ) )
value , err := asn1 . Marshal ( zBytes [ : sha256 . Size ] )
2018-09-15 17:16:35 +00:00
require . NoError ( t , err , "Expected marshaling of the keyAuth to return no error" )
2018-06-13 23:20:56 +00:00
if subtle . ConstantTimeCompare ( value [ : ] , ext . Value ) != 1 {
t . Errorf ( "Expected the challenge certificate id-pe-acmeIdentifier extension to contain the SHA-256 digest of the keyAuth, %v, but was %v" , zBytes [ : ] , ext . Value )
}
return nil
}
2018-09-15 17:16:35 +00:00
privKey , err := rsa . GenerateKey ( rand . Reader , 512 )
require . NoError ( t , err , "Could not generate test key" )
solver := & tlsALPNChallenge {
jws : & jws { privKey : privKey } ,
validate : mockValidate ,
provider : & TLSALPNProviderServer { port : "23457" } ,
2018-06-13 23:20:56 +00:00
}
2018-09-15 17:16:35 +00:00
clientChallenge := challenge { Type : string ( TLSALPN01 ) , Token : "tlsalpn1" }
err = solver . Solve ( clientChallenge , domain )
assert . NoError ( t , err )
2018-06-13 23:20:56 +00:00
}
func TestTLSALPNChallengeInvalidPort ( t * testing . T ) {
2018-09-15 17:16:35 +00:00
privKey , err := rsa . GenerateKey ( rand . Reader , 128 )
require . NoError ( t , err , "Could not generate test key" )
2018-06-13 23:20:56 +00:00
2018-09-15 17:16:35 +00:00
solver := & tlsALPNChallenge {
jws : & jws { privKey : privKey } ,
validate : stubValidate ,
provider : & TLSALPNProviderServer { port : "123456" } ,
2018-06-13 23:20:56 +00:00
}
2018-09-15 17:16:35 +00:00
clientChallenge := challenge { Type : string ( TLSALPN01 ) , Token : "tlsalpn1" }
err = solver . Solve ( clientChallenge , "localhost:123456" )
require . Error ( t , err )
assert . Contains ( t , err . Error ( ) , "invalid port" )
assert . Contains ( t , err . Error ( ) , "123456" )
2018-06-13 23:20:56 +00:00
}