// Extract the RSA public key from the Key record func (k *RR_DNSKEY) pubKeyRSA() *rsa.PublicKey { keybuf, err := packBase64([]byte(k.PublicKey)) if err != nil { return nil } // RFC 2537/3110, section 2. RSA Public KEY Resource Records // Length is in the 0th byte, unless its zero, then it // it in bytes 1 and 2 and its a 16 bit number explen := uint16(keybuf[0]) keyoff := 1 if explen == 0 { explen = uint16(keybuf[1])<<8 | uint16(keybuf[2]) keyoff = 3 } pubkey := new(rsa.PublicKey) pubkey.N = big.NewInt(0) shift := (explen - 1) * 8 for i := int(explen - 1); i >= 0; i-- { pubkey.E += int(keybuf[keyoff+i]) << shift shift -= 8 } pubkey.N.SetBytes(keybuf[keyoff+int(explen):]) return pubkey }
// msg -> rsa func UnpackKey(k *msgs.PublicKey) *rsa.PublicKey { var key rsa.PublicKey key.N = new(big.Int) key.N.SetBytes(k.N) key.E = int(*k.E) return &key }
// Call with tpm 2.0 and the quote handle, get the key back for serialization in AttestCertRequest. func GetRsaKeyFromHandle(rw io.ReadWriter, handle Handle) (*rsa.PublicKey, error) { publicBlob, _, _, err := ReadPublic(rw, handle) if err != nil { return nil, errors.New("Can't get public key blob") } rsaParams, err := DecodeRsaBuf(publicBlob) publicKey := new(rsa.PublicKey) // TODO(jlm): read exponent from blob publicKey.E = 0x00010001 M := new(big.Int) M.SetBytes(rsaParams.Modulus) publicKey.N = M return publicKey, nil }
// Convert string to an RSA public key func Base64ToPub(s string) (*rsa.PublicKey, os.Error) { if len(s) == 0 { return nil, nil } if !verifyCRC(s) { return nil, nil } s = s[0 : len(s)-1] enc := base64.StdEncoding pk := rsa.PublicKey{} buf := make([]byte, 4096) // shoud be big enough src := []byte(s) k := -1 // N if k = firstComma(src); k < 0 { return nil, os.ErrorString("missing delimiter") } n, err := enc.Decode(buf, src[0:k]) if err != nil { return nil, err } pk.N = &big.Int{} pk.N.SetBytes(buf[0:n]) src = src[k+1:] // E n, err = enc.Decode(buf, src) if err != nil { return nil, err } pke64, err := bytesToInt64(buf[0:n]) if err != nil { return nil, err } pk.E = int(pke64) return &pk, nil }
// parseRSA parses an RSA key according to RFC 4253, section 6.6. func parseRSA(in []byte) (out PublicKey, rest []byte, err error) { var w struct { E *big.Int N *big.Int Rest []byte `ssh:"rest"` } if err := Unmarshal(in, &w); err != nil { return nil, nil, err } if w.E.BitLen() > 24 { return nil, nil, errors.New("ssh: exponent too large") } e := w.E.Int64() if e < 3 || e&1 == 0 { return nil, nil, errors.New("ssh: incorrect exponent") } var key rsa.PublicKey key.E = int(e) key.N = w.N return (*rsaPublicKey)(&key), w.Rest, nil }
// publicKeyRSA returns the RSA public key from a DNSKEY record. func (k *RR_DNSKEY) publicKeyRSA() *rsa.PublicKey { keybuf, err := packBase64([]byte(k.PublicKey)) if err != nil { return nil } // RFC 2537/3110, section 2. RSA Public KEY Resource Records // Length is in the 0th byte, unless its zero, then it // it in bytes 1 and 2 and its a 16 bit number explen := uint16(keybuf[0]) keyoff := 1 if explen == 0 { explen = uint16(keybuf[1])<<8 | uint16(keybuf[2]) keyoff = 3 } pubkey := new(rsa.PublicKey) pubkey.N = big.NewInt(0) shift := uint64((explen - 1) * 8) expo := uint64(0) for i := int(explen - 1); i > 0; i-- { expo += uint64(keybuf[keyoff+i]) << shift shift -= 8 } // Remainder expo += uint64(keybuf[keyoff]) if expo > 2<<31 { // Larger expo than supported. // println("dns: F5 primes (or larger) are not supported") return nil } pubkey.E = int(expo) pubkey.N.SetBytes(keybuf[keyoff+int(explen):]) return pubkey }
func BuildAttestCertRequest(tpmDevice io.ReadWriter, quoteHandle Handle, endorsementHandle Handle, endorsementCert []byte, taoName string, ownerPw string) (*AttestCertRequest, error) { // Get Quote key. tpm2QuoteKeyBlob, tpm2QuoteKeyName, _, err := ReadPublic(tpmDevice, quoteHandle) if err != nil { return nil, err } rsaQuoteParams, err := DecodeRsaBuf(tpm2QuoteKeyBlob) if err != nil { return nil, err } quoteKey := new(rsa.PublicKey) quoteKey.N = new(big.Int) quoteKey.N.SetBytes(rsaQuoteParams.Modulus) quoteKey.E = int(rsaQuoteParams.Exp) request := new(AttestCertRequest) // DER encoded subject key derSubjectKey, err := x509.MarshalPKIXPublicKey(quoteKey) if err != nil { return nil, err } var hashedQuoteKey []byte if rsaQuoteParams.Hash_alg == AlgTPM_ALG_SHA1 { sha1Str := "sha1" request.HashType = &sha1Str sha1Hash := sha1.New() sha1Hash.Write([]byte(derSubjectKey)) hashedQuoteKey = sha1Hash.Sum(nil) } else if rsaQuoteParams.Hash_alg == AlgTPM_ALG_SHA256 { sha256Str := "sha256" request.HashType = &sha256Str sha256Hash := sha256.New() sha256Hash.Write([]byte(derSubjectKey)) hashedQuoteKey = sha256Hash.Sum(nil) } else { return nil, errors.New("RequestDomainQuoteCert: Quote key has unknown cert type") } sigAlg := uint16(AlgTPM_ALG_NULL) tpm2AttestBlob, tpm2SigBlob, err := Quote(tpmDevice, quoteHandle, ownerPw, ownerPw, hashedQuoteKey, []int{17, 18}, sigAlg) if err != nil { return nil, err } request.AttestBlob = tpm2AttestBlob request.SigBlob = tpm2SigBlob request.KeyName = &taoName request.SubjectPublicKey = derSubjectKey request.DerEndorsementCert = endorsementCert if rsaQuoteParams.Enc_alg == AlgTPM_ALG_RSA { rsaStr := "rsa" request.KeyType = &rsaStr } else { return nil, errors.New("RequestDomainQuoteCert: Bad quote key type") } request.Tpm2KeyName = tpm2QuoteKeyName // TODO: request.CertChain return request, nil }
func sshToPubkey(key string) (pubkey SSHKey) { verbose("Converting SSH input into a public key...", 3) /* An RSA SSH key can have leading key options (including quoted * whitespace) and trailing comments (including whitespace). We * take a short cut here and assume that if it contains the known * RSA pattern, then that field must be the actual key. This * would be a false assumption if one of the comments or options * contained that same pattern, but anybody who creates such a key * can fo screw themselves. */ i := strings.Index(key, OPENSSH_RSA_KEY_SUBSTRING) if i < 0 { fmt.Fprintf(os.Stderr, "Not an ssh RSA public key: '%v'\n", key) return } fields := strings.Split(key[i:], " ") decoded := decode(fields[1]) if len(decoded) < 1 { fmt.Fprintf(os.Stderr, "Unable to decode key.\n") return } /* Based on: * http://cpansearch.perl.org/src/MALLEN/Convert-SSH2-0.01/lib/Convert/SSH2.pm * https://gist.github.com/mahmoudimus/1654254, * http://golang.org/src/pkg/crypto/x509/x509.go * * See also: http://www.netmeister.org/blog/ssh2pkcs8.html * * The key format is base64 encoded tuples of: * - four bytes representing the length of the next data field * - the data field * * In practice, for an RSA key, we get: * - four bytes [0 0 0 7] * - the string "ssh-rsa" (7 bytes) * - four bytes * - the exponent * - four bytes * - the modulus */ var k rsa.PublicKey n := 0 for len(decoded) > 4 { var dlen uint32 bbuf := bytes.NewReader(decoded[:4]) err := binary.Read(bbuf, binary.BigEndian, &dlen) if err != nil { fmt.Printf("%v\n", err) continue } chunklen := int(dlen) + 4 if len(decoded) < chunklen { fmt.Fprintf(os.Stderr, "Invalid data while trying to extract public key.\n") fmt.Fprintf(os.Stderr, "Maybe a corrupted key?\n%v\n", key) return } data := decoded[4:chunklen] decoded = decoded[chunklen:] switch n { case 0: if ktype := fmt.Sprintf("%s", data); ktype != "ssh-rsa" { fmt.Fprintf(os.Stderr, "Unsupported key type (%v).\n", ktype) return } case 1: i := new(big.Int) i.SetString(fmt.Sprintf("0x%v", hex.EncodeToString(data)), 0) k.E = int(i.Int64()) case 2: i := new(big.Int) /* The value in this field is signed, so the first * byte should be 0, so we strip it. */ i.SetString(fmt.Sprintf("0x%v", hex.EncodeToString(data[1:])), 0) k.N = i } n++ } pubkey.Key = k pubkey.Fingerprint = getFingerPrint(k) return }
func main() { if len(os.Args) > 1 { log.Fatal("Unexpected arguments. This program can only read input from stdin.") } input, err := ioutil.ReadAll(os.Stdin) if err != nil { log.Fatal(err) } key := string(input) /* An RSA SSH key can have leading key options (including quoted * whitespace) and trailing comments (including whitespace). We * take a short cut here and assume that if it contains the known * RSA pattern, then that field must be the actual key. This * would be a false assumption if one of the comments or options * contained that same pattern, but anybody who creates such a key * can fo screw themselves. */ i := strings.Index(key, "ssh-rsa AAAAB3NzaC1") if i < 0 { log.Fatal("Input does not look like a valid SSH RSA key.") } fields := strings.Split(key[i:], " ") decoded, err := base64.StdEncoding.DecodeString(fields[1]) if err != nil { log.Fatal("Unable to decode key: %v", err) } /* Based on: * http://cpansearch.perl.org/src/MALLEN/Convert-SSH2-0.01/lib/Convert/SSH2.pm * https://gist.github.com/mahmoudimus/1654254, * http://golang.org/src/pkg/crypto/x509/x509.go * * The key format is base64 encoded tuples of: * - four bytes representing the length of the next data field * - the data field * * In practice, for an RSA key, we get: * - four bytes [0 0 0 7] * - the string "ssh-rsa" (7 bytes) * - four bytes * - the exponent * - four bytes * - the modulus */ n := 0 var pubkey rsa.PublicKey for len(decoded) > 0 { var dlen uint32 bbuf := bytes.NewReader(decoded[:4]) err := binary.Read(bbuf, binary.BigEndian, &dlen) if err != nil { log.Fatal(err) } data := decoded[4 : int(dlen)+4] decoded = decoded[4+int(dlen):] if n == 0 { if ktype := fmt.Sprintf("%s", data); ktype != "ssh-rsa" { log.Fatal("Unsupported key type (%v).", ktype) } } else if n == 1 { i := new(big.Int) i.SetString(fmt.Sprintf("0x%v", hex.EncodeToString(data)), 0) pubkey.E = int(i.Int64()) } else if n == 2 { i := new(big.Int) /* The value in this field is signed, so the first * byte should be 0, so we strip it. */ i.SetString(fmt.Sprintf("0x%v", hex.EncodeToString(data[1:])), 0) pubkey.N = i break } n += 1 } enc, err := asn1.Marshal(pubkey) if err != nil { log.Fatal("Unable to marshal pubkey (%v): %v", pubkey, err) } bitstring := asn1.BitString{enc, len(enc) * 8} type AlgorithmIdentifier struct { Algorithm asn1.ObjectIdentifier Parameters asn1.RawValue } var null = asn1.RawValue{Tag: 5} var pkid = AlgorithmIdentifier{asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}, null} type keyseq struct { Algorithm AlgorithmIdentifier BitString asn1.BitString } ks := keyseq{pkid, bitstring} enc, err = asn1.Marshal(ks) if err != nil { log.Fatal("Unable to marshal pubkey (%v): %v", pubkey, err) } fmt.Printf("-----BEGIN PUBLIC KEY-----\n") out := base64.StdEncoding.EncodeToString(enc) for len(out) > MAX_COLUMNS { fmt.Printf("%v\n", out[:MAX_COLUMNS]) out = out[MAX_COLUMNS:] } fmt.Printf("%v\n", out) fmt.Printf("-----END PUBLIC KEY-----\n") }
// Combined Endorsement/Activate test func TestCombinedEndorsementTest(t *testing.T) { hash_alg_id := uint16(AlgTPM_ALG_SHA1) // Open tpm rw, err := OpenTPM("/dev/tpm0") if err != nil { fmt.Printf("OpenTPM failed %s\n", err) return } // Flushall err = Flushall(rw) if err != nil { t.Fatal("Flushall failed\n") } // CreatePrimary var empty []byte primaryparms := RsaParams{uint16(AlgTPM_ALG_RSA), uint16(AlgTPM_ALG_SHA1), uint32(0x00030072), empty, uint16(AlgTPM_ALG_AES), uint16(128), uint16(AlgTPM_ALG_CFB), uint16(AlgTPM_ALG_NULL), uint16(0), uint16(2048), uint32(0x00010001), empty} parent_handle, public_blob, err := CreatePrimary(rw, uint32(OrdTPM_RH_OWNER), []int{0x7}, "", "", primaryparms) if err != nil { t.Fatal("CreatePrimary fails") } fmt.Printf("CreatePrimary succeeded\n") endorseParams, err := DecodeRsaArea(public_blob) if err != nil { t.Fatal("DecodeRsaBuf fails", err) } // CreateKey keyparms := RsaParams{uint16(AlgTPM_ALG_RSA), uint16(AlgTPM_ALG_SHA1), uint32(0x00030072), empty, uint16(AlgTPM_ALG_AES), uint16(128), uint16(AlgTPM_ALG_CFB), uint16(AlgTPM_ALG_NULL), uint16(0), uint16(2048), uint32(0x00010001), empty} private_blob, public_blob, err := CreateKey(rw, uint32(parent_handle), []int{7}, "", "01020304", keyparms) if err != nil { t.Fatal("CreateKey fails") } fmt.Printf("CreateKey succeeded\n") // Load key_handle, _, err := Load(rw, parent_handle, "", "", public_blob, private_blob) if err != nil { t.Fatal("Load fails") } fmt.Printf("Load succeeded\n") // ReadPublic _, name, _, err := ReadPublic(rw, key_handle) if err != nil { t.Fatal("ReadPublic fails") } fmt.Printf("ReadPublic succeeded\n") // Generate Credential credential := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10} fmt.Printf("Credential: %x\n", credential) // Internal MakeCredential credBlob, encrypted_secret0, err := InternalMakeCredential(rw, parent_handle, credential, name) if err != nil { FlushContext(rw, key_handle) FlushContext(rw, parent_handle) t.Fatal("Can't InternalMakeCredential\n") } // ActivateCredential recovered_credential1, err := ActivateCredential(rw, key_handle, parent_handle, "01020304", "", credBlob, encrypted_secret0) if err != nil { FlushContext(rw, key_handle) FlushContext(rw, parent_handle) t.Fatal("Can't ActivateCredential\n") } if bytes.Compare(credential, recovered_credential1) != 0 { FlushContext(rw, key_handle) FlushContext(rw, parent_handle) t.Fatal("Credential and recovered credential differ\n") } fmt.Printf("InternalMake/Activate test succeeds\n\n") protectorPublic := new(rsa.PublicKey) protectorPublic.E = 0x00010001 M := new(big.Int) M.SetBytes(endorseParams.Modulus) protectorPublic.N = M // MakeCredential encrypted_secret, encIdentity, integrityHmac, err := MakeCredential( protectorPublic, hash_alg_id, credential, name) if err != nil { FlushContext(rw, key_handle) FlushContext(rw, parent_handle) t.Fatal("Can't MakeCredential\n") } // ActivateCredential recovered_credential2, err := ActivateCredential(rw, key_handle, parent_handle, "01020304", "", append(integrityHmac, encIdentity...), encrypted_secret) if err != nil { FlushContext(rw, key_handle) FlushContext(rw, parent_handle) t.Fatal("Can't ActivateCredential\n") } if bytes.Compare(credential, recovered_credential2) != 0 { FlushContext(rw, key_handle) FlushContext(rw, parent_handle) t.Fatal("Credential and recovered credential differ\n") } fmt.Printf("Make/Activate test succeeds\n") // Flush FlushContext(rw, key_handle) }