add
9.0
top
← prev up next →

X.509 CertificatesπŸ”— i

(require x509 ) package: x509-lib

This library provides support for X.509 certificates, specifically the profiles and interpretations defined by [PKIX] and the CA/Browser Forum’s Baseline Requirements.

1Introduction to Using CertificatesπŸ”— i

The following example shows how to configure a certificate store with trusted root certificates, load a PEM file to create a certificate chain, and check whether the chain is suitable for identifying a TLS server.

First, let’s use openssl s_client to connect to https://www.racket-lang.org and save the certificates that the server sends in the TLS handshake:

openssl s_client -connect www.racket-lang.org:443 -showcerts \

< /dev/null > racket.pem

In general, the saved file will contain one or more PEM-encapsulated CERTIFICATE blocks: one for the server, and zero or more intermediate CA certificates necessary for building a certificate chain anchored by a trusted root CA.

If we try to load the PEM file using an empty certificate store, we get an error, because the store has no trusted roots:
> (send (empty-store )pem-file->chain"racket.pem")

pem-file->chain: failed to build complete chain

end certificate: #<certificate: C=US/ST=California/L=San

Francisco/O=Cloudflare, Inc./CN=sni.cloudflaressl.com>

We must configure a certificate store with a reasonable set of trusted roots. We must also enable some crypto factories so that the store can verify certificate signatures.
> (define store
(send (empty-store )add-trusted-from-openssl-directory"/etc/ssl/certs"))
Alternatively, we can use a store initialized with the OS’s default trusted certificates:
> (define store(default-store ))

Now we can create a certificate chain from the saved PEM file:
> (define racket-chain(send storepem-file->chain"racket.pem"))
We can extract the chain’s end certificate; we can also extract all of the certificates in the chain:
> (send racket-chainget-certificate)

#<certificate: C=US/ST=California/L=San Francisco/O=Cloudflare, Inc./CN=sni.cloudflaressl.com>

> (send racket-chainget-certificates)

'(#<certificate: C=US/ST=California/L=San Francisco/O=Cloudflare, Inc./CN=sni.cloudflaressl.com>

#<certificate: C=US/O=Cloudflare, Inc./CN=Cloudflare Inc ECC CA-3>

#<certificate: C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root>)

We check whether the certificate (more precisely, the certificate chain) is suitable for identifying a TLS server—and specifically, "www.racket-lang.org":
> (send racket-chainsuitable-for-tls-server?"www.racket-lang.org")

#t

> (send racket-chainsuitable-for-tls-server?"www.scheme.com")

#f

Finally, we can extract the end certificate’s public key:
> (define racket-pk(send racket-chainget-public-key))

2CertificatesπŸ”— i

A certificate represents an assertion that a cryptographic public key is tied to an identity, to be used for a particular purpose. The assertion is cryptographically signed by another party, the issuer.

For example, a secure web site (serving HTTP over TLS) would present a certificate with their public key, their identity in the form of their DNS name, and the purpose of identifying a TLS server. That certificate’s issuer would own a certificate for the purpose of acting as a certificate authority (CA), and its public key should verify the signature on the TLS server’s certificate.

One does not decide whether to trust a certificate in isolation; it depends on whether the issuer is trusted, and that often involves obtaining a certificate for the issuer and deciding whether to trust it, and so on. In general, trust is evaluated for a certificate chain; chains are built and evaluated using a certificate store.

procedure

( certificate? v)boolean?

v:any/c
Returns #t if v is a certificate, #f otherwise. Certificates implement the certificate<%> interface.

Public interface for certificates.
Note that (certificate? v) implies (is-a? vcertificate<%> ), but not vice versa. That is, a certificate object implements additional internal interfaces not exposed to users.
> (define racket-cert(send racket-chainget-certificate))
> racket-cert

#<certificate: C=US/ST=California/L=San Francisco/O=Cloudflare, Inc./CN=sni.cloudflaressl.com>

Two certificates are equal? if they have the same DER encodings.

method

(send a-certificate get-subject )any/c

Returns the Name of the certificate’s subject.

The result is a X.509 Name value represented according to the rules of the asn1 library. See [PKIX] for the definition of Name.

> (send racket-certget-subject)

'(rdnSequence

((#hasheq((type . (2 5 4 6)) (value . "US")))

(#hasheq((type . (2 5 4 8)) (value . (printableString "California"))))

(#hasheq((type . (2 5 4 7)) (value . (printableString "San Francisco"))))

(#hasheq((type . (2 5 4 10))

(value . (printableString "Cloudflare, Inc."))))

(#hasheq((type . (2 5 4 3))

(value . (printableString "sni.cloudflaressl.com"))))))

method

(send a-certificate get-issuer )any/c

Returns the Name of the certificate’s issuer.

> (send racket-certget-issuer)

'(rdnSequence

((#hasheq((type . (2 5 4 6)) (value . "US")))

(#hasheq((type . (2 5 4 10))

(value . (printableString "Cloudflare, Inc."))))

(#hasheq((type . (2 5 4 3))

(value . (printableString "Cloudflare Inc ECC CA-3"))))))

method

(send a-certificate get-subject-common-names )

Returns a list of Common Names (CN) occuring in the certificate’s subject. A typical certificate has at most one Common Name.

> (send racket-certget-subject-common-names)

'("sni.cloudflaressl.com")

method

(send a-certificate get-subject-alt-names [kind])

(listof any/c )
Returns a list of the certificate’s Subject Alternative Names (SAN).

If kind is a symbol, only subject alternative names of the given kind are returned, and they are returned untagged. If kind is #f, then all SAN entries are returned, and each entry is tagged with a kind symbol (see x509-general-name-tag/c ).

> (send racket-certget-subject-alt-names)

'((dNSName "sni.cloudflaressl.com")

(dNSName "racket-lang.org")

(dNSName "*.racket-lang.org"))

> (send racket-certget-subject-alt-names'dNSName)

'("sni.cloudflaressl.com" "racket-lang.org" "*.racket-lang.org")

method

(send a-certificate get-subject-name-string )string?

Returns a string summarizing the subject name of the certificate.

Warning: The format of the result may change in future versions of this library.

Example:
> (send racket-certget-subject-name-string)

"C=US/ST=California/L=San Francisco/O=Cloudflare, Inc./CN=sni.cloudflaressl.com"

method

(send a-certificate get-issuer-name-string )string?

Like get-subject-name-string , but returns a string representing the issuer.

Example:
> (send racket-certget-issuer-name-string)

"C=US/O=Cloudflare, Inc./CN=Cloudflare Inc ECC CA-3"

Returns the validity period of the certificate (from notBefore to notAfter) in seconds (see current-seconds , seconds->date , etc).

> (send racket-certget-validity-seconds)

'(1623448800 1654984799)

method

(send a-certificate get-spki )bytes?

Gets the DER encoding of the certificate’s SubjectPublicKeyInfo (SPKI).

This can be converted to a public key with datum->pk-key , but it is usually better to validate the certificate first and then call the chain’s get-public-key method.

method

(send a-certificate get-key-usages )

Gets the value of the KeyUsage extension, if present; if the extension is absent, returns null . See also ok-key-usage? in certificate-chain<%> .

> (send racket-certget-key-usages)

'(digitalSignature)

method

(send a-certificate get-extended-key-usages )

Gets the value of the ExtendedKeyUsage extension, if present; if the extension is absent, returns null . See also ok-extended-key-usage? in certificate-chain<%> .

> (send racket-certget-extended-key-usages)

'((1 3 6 1 5 5 7 3 1) (1 3 6 1 5 5 7 3 2))

method

(send a-certificate get-der )bytes?

Gets the DER encoding of the certificate.

procedure

( bytes->certificate bs)certificate?

bs:bytes?
Parses bs as a certificate. The byte string bs must contain exactly one DER-encoded certificate; otherwise, an exception is raised.

procedure

( read-pem-certificates in[#:countcount])(listof certificate? )

count:(or/c exact-nonnegative-integer? +inf.0)=+inf.0
Reads up to count certificates from in. The certificates must be encoded in the RFC 7468 textual format [RFC7468]. (This format is often conflated with “PEM”, although technically the two formats are not completely compatible.)

Certificates are delimited by "----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----" lines. Data outside of the delimiters is ignored and discarded, so certificates may be interleaved with other text. For example, the openssl s_client -showcerts command logs certificates intermixed with other diagnostic messages during TLS handshaking.

procedure

[ #:countcount])(listof certificate? )
pem-file:path-string?
count:(or/c exact-nonnegative-integer? +inf.0)=+inf.0
Like read-pem-certificates , but reads from the given pem-file.

Contract for symbols representing members of a KeyUsage extension value. Equivalent to
(or/c 'digitalSignature'nonRepudiation'keyEncipherment'dataEncipherment
'keyAgreement'keyCertSign'cRLSign'encipherOnly'decipherOnly)

Contract for symbols tagging kinds of GeneralName. Equivalent to
(or/c 'otherName'rfc822Name'dNSName'x400Address'directoryName
'ediPartyName'uniformResourceIdentifier'iPAddress'registeredID)

3Certificate ChainsπŸ”— i

A certificate chain contains a non-empty list of certificates, starting with an anchor (also called a trust anchor, and typically a root CA certificate) and ending with the end certificate — that is, the certificate whose identity, public key, and purpose are of interest to the application. The list of certificates satisfies the chain-validity properties:
  • Each certificate is the issuer of the next—that is, the subject name of each certificate “matches” [PKIX] the issuer name of the next certificate.

  • Each certificate that acts as an issuer (that is, every certificate in the chain except for the end certificate) is suitable as a CA certificate.

  • Each certificate’s public key verifies the signature of the next certificate in the chain. (Note that the anchor certificate’s signature is not checked; its trust is determined by the certificate store.)

  • The validity period of the chain is non-empty. The validity period of the chain is the intersection of the validity periods of all of the certificates in the chain. The certificates are not required to have strictly nested validity periods.

However, chain-validity is only a basic well-formedness property; it does not mean that the end certificate is valid for a given purpose. In particular:
  • A chain does not necessarily start with a trusted root CA.

  • A chain is not necessarily valid at the current time.

  • A chain’s end certificate is not necessarily valid for a given purpose (for example, for identifying particular a TLS server and creating a TLS connection).

Use trusted? to verify the first two properties and suitable-for-tls-server? to verify the third property (in the case of a TLS server).

Note: [PKIX] uses the term “certification path” instead of “certificate chain”.

procedure

( certificate-chain? v)boolean?

v:any/c
Returns #t if v is a certificate chain, #f otherwise. Certificate chains implement the certificate-chain<%> interface.

Public interface for certificate chains.
Note that (certificate-chain? v) implies (is-a? vcertificate-chain<%> ), but not vice versa. That is, a certificate chain object implements additional internal interfaces not exposed to users.

method

(send a-certificate-chain get-certificate )certificate?

Returns the chain’s end certificate — that is, the certificate that the chain certifies.

method

(send a-certificate-chain get-certificates )

Returns all of the certificates in a-certificate-chain, in “reversed” order: that is, the end certificate is the first element of the resulting list and the anchor is last.

method

(send a-certificate-chain get-issuer-chain )

Returns the prefix of the certificate chain corresponding to this certificate’s issuer, or #f if the current chain is an anchor.

method

(send a-certificate-chain get-anchor )certificate-chain?

Returns the certificate chain’s anchor.

method

(send a-certificate-chain is-anchor? )boolean?

Returns #t if a-certificate-chain is an anchor, #f otherwise. An anchor is a chain that has no issuer chain.

method

(send a-certificate-chain get-subject )any/c

Equivalent to

(send (send a-certificate-chainget-certificate )get-subject )

method

(send a-certificate-chain get-subject-alt-names [kind])

(listof any/c )
kind:(or/c symbol? #f)=#f
Equivalent to
(send (send a-certificate-chainget-certificate )

method

(send a-certificate-chain get-public-key [factories])

Creates a public key from the end certificate’s SubjectPublicKeyInfo using an implementation from factories.

method

(send a-certificate-chain check-signature algid
msg
sig)
algid:(or/c bytes? asn1-algorithm-identifier/c)
msg:bytes?
sig:bytes?
Verifies that the signature sig is valid for the data msg using the end certificate’s public key and the signature algorithm specified by algid (an AlgorithmIdentifier, either DER-encoded as a byte string or the parsed representation).

The result is one of the following:
  • The result is (ok #t) if the signature is valid.

  • The result is (bad faults) if verification failed, where faults is a list of symbols describing the failure. The symbol 'signature:bad indicates a bad signature; other symbols indicate situations like problems interpreting algid and mismatches between the public key and the algorithm specified by algid.

method

(send a-certificate-chain get-security-level )

Returns the security level of the chain. Equivalent to

Example:
> (send racket-chainget-security-level)

2

method

(send a-certificate-chain get-security-strength )

Returns the security strength of the chain, which is the minimum of the strengths of each public key and signature in the chain, except for the signature within the anchor.

Example:
> (send racket-chainget-security-strength)

112

Returns the security strength of the end certificate’s public key. Equivalent to

(pk-security-strength (send a-certificate-chainget-public-key ))

Example:
> (send racket-chainget-public-key-security-strength)

128

method

(send a-certificate-chain trusted?
store
[ from-time
to-time
#:security-levelsecurity-level])
to-time:exact-integer? =from-time
security-level:security-level/c =2
Returns #t if the chain’s anchor certificate is trusted according to store, the validity of the chain includes the period from from-time to to-time, and the security level of all public keys and signatures in the chain is at least security-level; otherwise, returns #f.

Equivalent to
(ok? (send a-certificate-chaincheck-trust storefrom-timeto-time
#:security-levelsecurity-level))

method

(send a-certificate-chain check-trust
store
[ from-time
to-time
#:security-levelsecurity-level])
to-time:exact-integer? =from-time
security-level:security-level/c =2
Similar to trusted? , but the result is one of the following:
  • The result is (ok #t) if the chain’s anchor certificate is trusted by store, the validity of the chain includes the period from from-time to to-time, and the security level of all public keys and signatures in the chain is at least security-level.

  • The result is (bad (list (cons cert-indexfault)... )) otherwise, where each cert-index is the index of the certificate where the problem occurred (starting with 0 for the anchor) and fault is a value (usually a symbol) describing the problem.

Examples:
> (send racket-chaincheck-trust(default-store )#:security-level2)

'#s(ok #t)

> (send racket-chaincheck-trust(empty-store )#:security-level3)

'#s(bad ((0 . anchor:not-trusted) (0 . security-level:weak-public-key)))

method

(send a-certificate-chain get-validity-seconds )

Gets the validity period of the chain, which is the intersection of the validity periods of all certificates in the chain.

Example:
> (send racket-chainget-validity-seconds)

'(1623448800 1654984799)

method

(send a-certificate-chain ok-key-usage? usage
[ default])any/c
usage:key-usage/c
default:any/c =#f
Returns #t if the end certificate has the KeyUsage extension and the extension’s value contains the key usage named by usage. If the extension is present but does not contain usage, returns #f. If the end certificate does not have a KeyUsage extension, returns default.

Examples:
> (send racket-chainok-key-usage?'digitalSignature)

#t

> (send racket-chainok-key-usage?'keyCertSign)

#f

> (let ([ca-chain(send racket-chainget-issuer-chain)])
(send ca-chainok-key-usage?'keyCertSign))

#t

method

(send a-certificate-chain ok-extended-key-usage? eku)

eku:asn1-oid?
Returns #t if the extended key usage identified by eku (an OBJECT IDENTIFIER) is allowed for the end certificate of a-certificate-chain; returns #f otherwise.

The extended key usage eku is allowed if all of the following are true:
  • The end certificate contains an ExtendedKeyUsage extension and the extension’s value contains eku.

  • In every preceding certificate in the chain (that is, the anchor and intermediate CA certificates), if the ExtendedKeyUsage extension is present, then its value contains eku.

Note: this method does not treat anyExtendedKeyUsage specially.

Examples:
> (define id-kp-serverAuth'(136155731))
> (send racket-chainok-extended-key-usage?id-kp-serverAuth)

#t

> (define id-kp-codeSigning'(136155733))
> (send racket-chainok-extended-key-usage?id-kp-codeSigning)

#f

method

(send a-certificate-chain suitable-for-CA? )boolean?

Returns #t if the chain ends with a certificate that is suitable for a certificate authority — specifically, for signing other certificates. Returns #f otherwise.

Examples:
> (send racket-chainsuitable-for-CA?)

#f

> (let ([issuer-chain(send racket-chainget-issuer-chain)])
(send issuer-chainsuitable-for-CA?))

#t

method

(send a-certificate-chain suitable-for-tls-server? host)

host:(or/c string? #f)
Returns #t if the chain ends with a certificate that is suitable for identifying a TLS server, and if the certificate has a subject alternative name (SAN) that matches the given host DNS name; otherwise, returns #f. If host is #f, the DNS name check is omitted.

Examples:
> (send racket-chainsuitable-for-tls-server?"racket-lang.org")

#t

> (send racket-chainsuitable-for-tls-server?"example.com")

#f

> (send racket-chainsuitable-for-tls-server?#f)

#t

method

(send a-certificate-chain suitable-for-tls-client? name)

name:any/c
Returns #t if the chain’s certificate is suitable for identifying a client to a TLS server, and if the certificate has a subject name or subject alternative name (SAN) that matches the given name; otherwise, returns #f. If name is #f, then the name check is omitted.

4Certificate StoresπŸ”— i

A certificate store determines which certificates are trusted a priori—usually, these trusted certificates correspond to root CAs, which are typically self-issued and self-signed. In this context, “trusted” means that the assertion that the certificate represents (binding a public key to identities and purposes) is accepted at face value; it does not mean that the certificate is automatically accepted as suitable for every purpose.

The store may also contain certificates that are not directly trusted, but may be used in the construction of chains.

procedure

( certificate-store? v)boolean?

v:any/c
Returns #f if v is a certificate store, #f otherwise. Certificate stores implement the certificate-store<%> interface.

procedure

( empty-store [#:security-levelsecurity-level])

security-level:security-level/c =2
Returns a certificate store containing no certificates (trusted or untrusted). The store’s security level is initialized to security-level.

procedure

( default-store [#:security-levelsecurity-level])

security-level:security-level/c =2
Returns a certificate store initialized with trusted certificates from the OS. The store’s security level is initialized to security-level. The trusted certificates are the same as those specified by the openssl library’s (ssl-default-verify-sources ) initial value.

Public interface for certificate stores.
Note that (certificate-store? v) implies (is-a? vcertificate-store<%> ), but not vice versa. That is, a certificate store object implements additional internal interfaces not exposed to users.

method

(send a-certificate-store add [ #:trustedtrusted-certs
#:untrusteduntrusted-certs])
trusted-certs:(listof certificate? )=null
untrusted-certs:(listof certificate? )=null
Creates a new certificate store like a-certificate-store but where
  • The trusted-certs and untrusted-certs are available for building certificate chains.

  • The trusted-certs are considered trusted.

Note: trust is monotonic. That is, if a certificate is already trusted, then adding it again as an untrusted certificate does not make it untrusted.

method

(send a-certificate-store add-trusted-from-pem-file pem-file)

pem-file:path-string?
Creates a new certificate store like a-certificate-store, but trusting the certificates contained in PEM format in pem-file.

Creates a new certificate store like a-certificate-store, but trusting the certificates in dir, which uses OpenSSL-style hashing.

method

(send a-certificate-store build-chain end-cert
[ other-untrusted-certs
valid-time])
end-cert:certificate?
other-untrusted-certs:(listof certificate? )=null
Builds a certificate chain starting with some trusted certificate and ending with end-cert. The chain may be built from intermediate certificates from other-untrusted-certs in addition to the certificates already in the store. The result chain is chain-valid; it is valid for a period including valid-time; and its anchor is trusted by a-certificate-store.

If no such chain can be constructed, an exception is raised. If multiple chains can be constructed, one is selected, but there are no guarantees about how it is selected.

method

(send a-certificate-store build-chains end-cert
[ other-untrusted-certs
valid-time
#:empty-ok?empty-ok?])
end-cert:certificate?
other-untrusted-certs:(listof certificate? )=null
empty-ok?:boolean? =#f
Like build-chain , but returns all chains that could be constructed. If no such chains can be constructed, an exception is raised, unless empty-ok? is true, in which case null is returned.

method

(send a-certificate-store pem-file->chain pem-file
[ valid-time])
pem-file:path-string?
Returns a certificate chain for the first certificate in PEM format in pem-file, using any remaining certificates in the file as other untrusted certificates. The result chain is chain-valid; it is valid for a period including valid-time; and its anchor is trusted by a-certificate-store.

5Certificate Revocation CheckingπŸ”— i

There are two main certificate revocation mechanisms: CRLs (Certificate Revocation Lists) and OCSP (Online Certificate Status Protocol).

Examples:
> (define rev(make-revocation-checker 'temporary#:fetch-crl?#f))
> (send revcheck-ocspracket-chain)

'#s(ok #t)

> (send revcheck-crlracket-chain)

'#s(bad unknown)

procedure

[ #:trust-db?trust-db?
#:fetch-ocsp?fetch-ocsp?
#:fetch-crl?fetch-crl?])
db-file:(or/c path-string? 'memory'temporary)
trust-db?:boolean? =#t
fetch-ocsp?:boolean? =#t
fetch-crl?:boolean? =#t
Returns an object for performing certificate revocation checks using OCSP and CRLs.

The db-file is a SQLite3 database file used to cache OCSP and CRL responses. These responses carry signatures, so they can be cached even if the cache is untrusted. (When the cache contains a response, the response is re-verified, and if verification fails then the cached response is discarded and a new response is retrieved.)

If trust-db? is #t, then status information about individual certificates is also cached. This saves parsing and signature verification time, but these individual status records do not carry signatures, so they cannot be re-verified later. If trust-db? is #f, then only the re-verifiable parts of the cache are used.

If fetch-ocsp? is #t, then if the cache does not contain a trusted, unexpired OCSP response, a response is fetched from the OCSP responder URL (or URLs) in the certificate being checked. If fetch-ocsp? is #f, no new response is fetched; if a suitable response is not in the cache, the certificate’s status is unknown. Likewise, the fetch-crl? option controls requests for CRLs.

Public interface for checking revocation of certificates.
Both the check-ocsp and check-crl methods take certificate chains rather than certificates, because verifying revocation responses requires the public key of the certificate’s issuer. Both methods check only the end certificate of the chain for revocation.

method

(send a-revocation-checker check-ocsp chain)

(result/c #t(or/c 'revoked'unknown'no-sources))
Returns one of the following:
  • (ok #t) — Some OCSP response indicated that the end certificate is good.

  • (bad 'revoked) — Some OCSP response indicated that the end certificate is revoked.

  • (bad 'unknown) — No responder produced a valid response, or the response indicated that the responder does not know the certificate’s status.

  • (bad 'no-sources) — The certificate has no usable OCSP responder URLs. This library uses only URLs with the scheme "http" or "https".

method

(send a-revocation-checker check-crl chain)

(result/c #t(listof (or/c 'revoked'unknown'no-sources)))
Returns one of the following:
  • (ok #t) — All usable CRLs were checked and the end certificate of chain was absent from all of the revocation lists.

  • (bad 'revoked) — Some CRL indicated that the certificate is revoked.

  • (bad 'unknown) — Some CRL source was unavailable or contained an invalid CRL, either because retrieving it failed (perhaps due to a network failure or server problem), or the retrieved CRL had a bad signature, or a-revocation-checker was configured not to fetch CRLs and it was not in the cache.

  • (bad 'no-sources) — The certificate has no usable CRL sources. This library uses only URLs with the scheme "http" or "https".

BibliographyπŸ”— i

[PKIX] “RFC 5280: Internet X.509 Public Key Infrastructure: Certificate and CRL Profile.” https://tools.ietf.org/html/rfc5280
[RFC7468] “Textual Encodings of PKIX, PKCS, and CMS Structures.” https://tools.ietf.org/html/rfc7468
[CAB-BR] “Baseline Requirements for the Issuance and Management of Publicly-Trusted Certificates.” https://cabforum.org/baseline-requirements-documents/
[OCSP] “RFC 6960: X.509 Internet Public Key Infrastructure Online Certificate Status Protocol - OCSP.” https://tools.ietf.org/html/rfc6960
[LightOCSP] “RFC 5019: The Lightweight Online Certificate Status Protocol (OCSP) Profile for High-Volume Environments.” https://tools.ietf.org/html/rfc5019
[SP800-57-1] “NIST Special Publication 800-57 Part 1 Revision 5: Recommendation for Key Management: Part 1 - General.” https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-5/final

top
← prev up next →

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /