| package libtrust |
| |
| import ( |
| "crypto" |
| "crypto/rand" |
| "crypto/rsa" |
| "crypto/x509" |
| "encoding/json" |
| "encoding/pem" |
| "errors" |
| "fmt" |
| "io" |
| "math/big" |
| ) |
| |
| /* |
| * RSA DSA PUBLIC KEY |
| */ |
| |
| // rsaPublicKey implements a JWK Public Key using RSA digital signature algorithms. |
| type rsaPublicKey struct { |
| *rsa.PublicKey |
| extended map[string]interface{} |
| } |
| |
| func fromRSAPublicKey(cryptoPublicKey *rsa.PublicKey) *rsaPublicKey { |
| return &rsaPublicKey{cryptoPublicKey, map[string]interface{}{}} |
| } |
| |
| // KeyType returns the JWK key type for RSA keys, i.e., "RSA". |
| func (k *rsaPublicKey) KeyType() string { |
| return "RSA" |
| } |
| |
| // KeyID returns a distinct identifier which is unique to this Public Key. |
| func (k *rsaPublicKey) KeyID() string { |
| return keyIDFromCryptoKey(k) |
| } |
| |
| func (k *rsaPublicKey) String() string { |
| return fmt.Sprintf("RSA Public Key <%s>", k.KeyID()) |
| } |
| |
| // Verify verifyies the signature of the data in the io.Reader using this Public Key. |
| // The alg parameter should be the name of the JWA digital signature algorithm |
| // which was used to produce the signature and should be supported by this |
| // public key. Returns a nil error if the signature is valid. |
| func (k *rsaPublicKey) Verify(data io.Reader, alg string, signature []byte) error { |
| // Verify the signature of the given date, return non-nil error if valid. |
| sigAlg, err := rsaSignatureAlgorithmByName(alg) |
| if err != nil { |
| return fmt.Errorf("unable to verify Signature: %s", err) |
| } |
| |
| hasher := sigAlg.HashID().New() |
| _, err = io.Copy(hasher, data) |
| if err != nil { |
| return fmt.Errorf("error reading data to sign: %s", err) |
| } |
| hash := hasher.Sum(nil) |
| |
| err = rsa.VerifyPKCS1v15(k.PublicKey, sigAlg.HashID(), hash, signature) |
| if err != nil { |
| return fmt.Errorf("invalid %s signature: %s", sigAlg.HeaderParam(), err) |
| } |
| |
| return nil |
| } |
| |
| // CryptoPublicKey returns the internal object which can be used as a |
| // crypto.PublicKey for use with other standard library operations. The type |
| // is either *rsa.PublicKey or *ecdsa.PublicKey |
| func (k *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { |
| return k.PublicKey |
| } |
| |
| func (k *rsaPublicKey) toMap() map[string]interface{} { |
| jwk := make(map[string]interface{}) |
| for k, v := range k.extended { |
| jwk[k] = v |
| } |
| jwk["kty"] = k.KeyType() |
| jwk["kid"] = k.KeyID() |
| jwk["n"] = joseBase64UrlEncode(k.N.Bytes()) |
| jwk["e"] = joseBase64UrlEncode(serializeRSAPublicExponentParam(k.E)) |
| |
| return jwk |
| } |
| |
| // MarshalJSON serializes this Public Key using the JWK JSON serialization format for |
| // RSA keys. |
| func (k *rsaPublicKey) MarshalJSON() (data []byte, err error) { |
| return json.Marshal(k.toMap()) |
| } |
| |
| // PEMBlock serializes this Public Key to DER-encoded PKIX format. |
| func (k *rsaPublicKey) PEMBlock() (*pem.Block, error) { |
| derBytes, err := x509.MarshalPKIXPublicKey(k.PublicKey) |
| if err != nil { |
| return nil, fmt.Errorf("unable to serialize RSA PublicKey to DER-encoded PKIX format: %s", err) |
| } |
| k.extended["kid"] = k.KeyID() // For display purposes. |
| return createPemBlock("PUBLIC KEY", derBytes, k.extended) |
| } |
| |
| func (k *rsaPublicKey) AddExtendedField(field string, value interface{}) { |
| k.extended[field] = value |
| } |
| |
| func (k *rsaPublicKey) GetExtendedField(field string) interface{} { |
| v, ok := k.extended[field] |
| if !ok { |
| return nil |
| } |
| return v |
| } |
| |
| func rsaPublicKeyFromMap(jwk map[string]interface{}) (*rsaPublicKey, error) { |
| // JWK key type (kty) has already been determined to be "RSA". |
| // Need to extract 'n', 'e', and 'kid' and check for |
| // consistency. |
| |
| // Get the modulus parameter N. |
| nB64Url, err := stringFromMap(jwk, "n") |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Public Key modulus: %s", err) |
| } |
| |
| n, err := parseRSAModulusParam(nB64Url) |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Public Key modulus: %s", err) |
| } |
| |
| // Get the public exponent E. |
| eB64Url, err := stringFromMap(jwk, "e") |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Public Key exponent: %s", err) |
| } |
| |
| e, err := parseRSAPublicExponentParam(eB64Url) |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Public Key exponent: %s", err) |
| } |
| |
| key := &rsaPublicKey{ |
| PublicKey: &rsa.PublicKey{N: n, E: e}, |
| } |
| |
| // Key ID is optional, but if it exists, it should match the key. |
| _, ok := jwk["kid"] |
| if ok { |
| kid, err := stringFromMap(jwk, "kid") |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Public Key ID: %s", err) |
| } |
| if kid != key.KeyID() { |
| return nil, fmt.Errorf("JWK RSA Public Key ID does not match: %s", kid) |
| } |
| } |
| |
| if _, ok := jwk["d"]; ok { |
| return nil, fmt.Errorf("JWK RSA Public Key cannot contain private exponent") |
| } |
| |
| key.extended = jwk |
| |
| return key, nil |
| } |
| |
| /* |
| * RSA DSA PRIVATE KEY |
| */ |
| |
| // rsaPrivateKey implements a JWK Private Key using RSA digital signature algorithms. |
| type rsaPrivateKey struct { |
| rsaPublicKey |
| *rsa.PrivateKey |
| } |
| |
| func fromRSAPrivateKey(cryptoPrivateKey *rsa.PrivateKey) *rsaPrivateKey { |
| return &rsaPrivateKey{ |
| *fromRSAPublicKey(&cryptoPrivateKey.PublicKey), |
| cryptoPrivateKey, |
| } |
| } |
| |
| // PublicKey returns the Public Key data associated with this Private Key. |
| func (k *rsaPrivateKey) PublicKey() PublicKey { |
| return &k.rsaPublicKey |
| } |
| |
| func (k *rsaPrivateKey) String() string { |
| return fmt.Sprintf("RSA Private Key <%s>", k.KeyID()) |
| } |
| |
| // Sign signs the data read from the io.Reader using a signature algorithm supported |
| // by the RSA private key. If the specified hashing algorithm is supported by |
| // this key, that hash function is used to generate the signature otherwise the |
| // the default hashing algorithm for this key is used. Returns the signature |
| // and the name of the JWK signature algorithm used, e.g., "RS256", "RS384", |
| // "RS512". |
| func (k *rsaPrivateKey) Sign(data io.Reader, hashID crypto.Hash) (signature []byte, alg string, err error) { |
| // Generate a signature of the data using the internal alg. |
| sigAlg := rsaPKCS1v15SignatureAlgorithmForHashID(hashID) |
| hasher := sigAlg.HashID().New() |
| |
| _, err = io.Copy(hasher, data) |
| if err != nil { |
| return nil, "", fmt.Errorf("error reading data to sign: %s", err) |
| } |
| hash := hasher.Sum(nil) |
| |
| signature, err = rsa.SignPKCS1v15(rand.Reader, k.PrivateKey, sigAlg.HashID(), hash) |
| if err != nil { |
| return nil, "", fmt.Errorf("error producing signature: %s", err) |
| } |
| |
| alg = sigAlg.HeaderParam() |
| |
| return |
| } |
| |
| // CryptoPrivateKey returns the internal object which can be used as a |
| // crypto.PublicKey for use with other standard library operations. The type |
| // is either *rsa.PublicKey or *ecdsa.PublicKey |
| func (k *rsaPrivateKey) CryptoPrivateKey() crypto.PrivateKey { |
| return k.PrivateKey |
| } |
| |
| func (k *rsaPrivateKey) toMap() map[string]interface{} { |
| k.Precompute() // Make sure the precomputed values are stored. |
| jwk := k.rsaPublicKey.toMap() |
| |
| jwk["d"] = joseBase64UrlEncode(k.D.Bytes()) |
| jwk["p"] = joseBase64UrlEncode(k.Primes[0].Bytes()) |
| jwk["q"] = joseBase64UrlEncode(k.Primes[1].Bytes()) |
| jwk["dp"] = joseBase64UrlEncode(k.Precomputed.Dp.Bytes()) |
| jwk["dq"] = joseBase64UrlEncode(k.Precomputed.Dq.Bytes()) |
| jwk["qi"] = joseBase64UrlEncode(k.Precomputed.Qinv.Bytes()) |
| |
| otherPrimes := k.Primes[2:] |
| |
| if len(otherPrimes) > 0 { |
| otherPrimesInfo := make([]interface{}, len(otherPrimes)) |
| for i, r := range otherPrimes { |
| otherPrimeInfo := make(map[string]string, 3) |
| otherPrimeInfo["r"] = joseBase64UrlEncode(r.Bytes()) |
| crtVal := k.Precomputed.CRTValues[i] |
| otherPrimeInfo["d"] = joseBase64UrlEncode(crtVal.Exp.Bytes()) |
| otherPrimeInfo["t"] = joseBase64UrlEncode(crtVal.Coeff.Bytes()) |
| otherPrimesInfo[i] = otherPrimeInfo |
| } |
| jwk["oth"] = otherPrimesInfo |
| } |
| |
| return jwk |
| } |
| |
| // MarshalJSON serializes this Private Key using the JWK JSON serialization format for |
| // RSA keys. |
| func (k *rsaPrivateKey) MarshalJSON() (data []byte, err error) { |
| return json.Marshal(k.toMap()) |
| } |
| |
| // PEMBlock serializes this Private Key to DER-encoded PKIX format. |
| func (k *rsaPrivateKey) PEMBlock() (*pem.Block, error) { |
| derBytes := x509.MarshalPKCS1PrivateKey(k.PrivateKey) |
| k.extended["keyID"] = k.KeyID() // For display purposes. |
| return createPemBlock("RSA PRIVATE KEY", derBytes, k.extended) |
| } |
| |
| func rsaPrivateKeyFromMap(jwk map[string]interface{}) (*rsaPrivateKey, error) { |
| // The JWA spec for RSA Private Keys (draft rfc section 5.3.2) states that |
| // only the private key exponent 'd' is REQUIRED, the others are just for |
| // signature/decryption optimizations and SHOULD be included when the JWK |
| // is produced. We MAY choose to accept a JWK which only includes 'd', but |
| // we're going to go ahead and not choose to accept it without the extra |
| // fields. Only the 'oth' field will be optional (for multi-prime keys). |
| privateExponent, err := parseRSAPrivateKeyParamFromMap(jwk, "d") |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Private Key exponent: %s", err) |
| } |
| firstPrimeFactor, err := parseRSAPrivateKeyParamFromMap(jwk, "p") |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Private Key prime factor: %s", err) |
| } |
| secondPrimeFactor, err := parseRSAPrivateKeyParamFromMap(jwk, "q") |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Private Key prime factor: %s", err) |
| } |
| firstFactorCRT, err := parseRSAPrivateKeyParamFromMap(jwk, "dp") |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Private Key CRT exponent: %s", err) |
| } |
| secondFactorCRT, err := parseRSAPrivateKeyParamFromMap(jwk, "dq") |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Private Key CRT exponent: %s", err) |
| } |
| crtCoeff, err := parseRSAPrivateKeyParamFromMap(jwk, "qi") |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Private Key CRT coefficient: %s", err) |
| } |
| |
| var oth interface{} |
| if _, ok := jwk["oth"]; ok { |
| oth = jwk["oth"] |
| delete(jwk, "oth") |
| } |
| |
| // JWK key type (kty) has already been determined to be "RSA". |
| // Need to extract the public key information, then extract the private |
| // key values. |
| publicKey, err := rsaPublicKeyFromMap(jwk) |
| if err != nil { |
| return nil, err |
| } |
| |
| privateKey := &rsa.PrivateKey{ |
| PublicKey: *publicKey.PublicKey, |
| D: privateExponent, |
| Primes: []*big.Int{firstPrimeFactor, secondPrimeFactor}, |
| Precomputed: rsa.PrecomputedValues{ |
| Dp: firstFactorCRT, |
| Dq: secondFactorCRT, |
| Qinv: crtCoeff, |
| }, |
| } |
| |
| if oth != nil { |
| // Should be an array of more JSON objects. |
| otherPrimesInfo, ok := oth.([]interface{}) |
| if !ok { |
| return nil, errors.New("JWK RSA Private Key: Invalid other primes info: must be an array") |
| } |
| numOtherPrimeFactors := len(otherPrimesInfo) |
| if numOtherPrimeFactors == 0 { |
| return nil, errors.New("JWK RSA Privake Key: Invalid other primes info: must be absent or non-empty") |
| } |
| otherPrimeFactors := make([]*big.Int, numOtherPrimeFactors) |
| productOfPrimes := new(big.Int).Mul(firstPrimeFactor, secondPrimeFactor) |
| crtValues := make([]rsa.CRTValue, numOtherPrimeFactors) |
| |
| for i, val := range otherPrimesInfo { |
| otherPrimeinfo, ok := val.(map[string]interface{}) |
| if !ok { |
| return nil, errors.New("JWK RSA Private Key: Invalid other prime info: must be a JSON object") |
| } |
| |
| otherPrimeFactor, err := parseRSAPrivateKeyParamFromMap(otherPrimeinfo, "r") |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Private Key prime factor: %s", err) |
| } |
| otherFactorCRT, err := parseRSAPrivateKeyParamFromMap(otherPrimeinfo, "d") |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Private Key CRT exponent: %s", err) |
| } |
| otherCrtCoeff, err := parseRSAPrivateKeyParamFromMap(otherPrimeinfo, "t") |
| if err != nil { |
| return nil, fmt.Errorf("JWK RSA Private Key CRT coefficient: %s", err) |
| } |
| |
| crtValue := crtValues[i] |
| crtValue.Exp = otherFactorCRT |
| crtValue.Coeff = otherCrtCoeff |
| crtValue.R = productOfPrimes |
| otherPrimeFactors[i] = otherPrimeFactor |
| productOfPrimes = new(big.Int).Mul(productOfPrimes, otherPrimeFactor) |
| } |
| |
| privateKey.Primes = append(privateKey.Primes, otherPrimeFactors...) |
| privateKey.Precomputed.CRTValues = crtValues |
| } |
| |
| key := &rsaPrivateKey{ |
| rsaPublicKey: *publicKey, |
| PrivateKey: privateKey, |
| } |
| |
| return key, nil |
| } |
| |
| /* |
| * Key Generation Functions. |
| */ |
| |
| func generateRSAPrivateKey(bits int) (k *rsaPrivateKey, err error) { |
| k = new(rsaPrivateKey) |
| k.PrivateKey, err = rsa.GenerateKey(rand.Reader, bits) |
| if err != nil { |
| return nil, err |
| } |
| |
| k.rsaPublicKey.PublicKey = &k.PrivateKey.PublicKey |
| k.extended = make(map[string]interface{}) |
| |
| return |
| } |
| |
| // GenerateRSA2048PrivateKey generates a key pair using 2048-bit RSA. |
| func GenerateRSA2048PrivateKey() (PrivateKey, error) { |
| k, err := generateRSAPrivateKey(2048) |
| if err != nil { |
| return nil, fmt.Errorf("error generating RSA 2048-bit key: %s", err) |
| } |
| |
| return k, nil |
| } |
| |
| // GenerateRSA3072PrivateKey generates a key pair using 3072-bit RSA. |
| func GenerateRSA3072PrivateKey() (PrivateKey, error) { |
| k, err := generateRSAPrivateKey(3072) |
| if err != nil { |
| return nil, fmt.Errorf("error generating RSA 3072-bit key: %s", err) |
| } |
| |
| return k, nil |
| } |
| |
| // GenerateRSA4096PrivateKey generates a key pair using 4096-bit RSA. |
| func GenerateRSA4096PrivateKey() (PrivateKey, error) { |
| k, err := generateRSAPrivateKey(4096) |
| if err != nil { |
| return nil, fmt.Errorf("error generating RSA 4096-bit key: %s", err) |
| } |
| |
| return k, nil |
| } |