So I have completed all the signing and compressing process for Apple passes and have been able to connect the pass to my server for updating. The only problem I have left to solve is implementing push notifications.
I have been trying for a couple of days now but just can't seem to manage and I think I am missing something really simple. I am not too proficient with networking so I would really appreciate the help.
This is the log I get from guzzle with my best try.
Trying 17.188.136.150:443... * TCP_NODELAY set * Connected to api.push.apple.com (17.188.136.150) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /usr/local/etc/openssl/cert.pem CApath: /usr/local/etc/openssl#1.1/certs * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305 * ALPN, server accepted to use h2 * Server certificate: * subject: CN=api.push.apple.com; OU=management:idms.group.533599; O=Apple Inc.; ST=California; C=US * start date: Mar 14 17:50:10 2019 GMT * expire date: Apr 12 17:50:10 2021 GMT * subjectAltName: host "api.push.apple.com" matched cert's "api.push.apple.com" * issuer: CN=Apple IST CA 2 - G1; OU=Certification Authority; O=Apple Inc.; C=US * SSL certificate verify ok. * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Failed sending HTTP POST request * Connection #0 to host api.push.apple.com left intact
I am using the same certificate I used for the pass I am trying to update and am sending the device token I received upon registering the pass. This is my php code.
$client = new Client();
try {
$result = $client->post('https://api.push.apple.com:443', [
'headers' => ['apns-id' => <pass_type_id> , ':path' => '/3/device/<device_id_received_upon_registration>'],
'json' => ['apns'=>''],
'debug'=>true,
'version'=>2.0,
'ssl_key' => [<path_to_key>, <key_password>],
'cert' => [<path_to_certificate (same one used for signing pass)>, <certificate_password>]]);
}
catch (GuzzleHttp\Exception\ClientException $e) {
dd($e);
}
I am really lost with this one. Please help me out. I also tried connecting to port 1295 with some other code I copy pasted but it wasn't working as it should and had even more difficulty debugging as I am more familiar with port 443.
It works for me, with small changes:
$pem_file = '<path_to_your_pem_file_including_private_key>';
$pem_secret = '<private_key_password>';
$url = "https://api.push.apple.com/3/device/" . $device_push_token;
$response = $client->post($url, [
'headers' => ['apns-topic' => $pass_type_id],
'json' => json_decode('{}'),
'debug' => true,
'version' => 2.0,
'cert' => [$pem_file, $pem_secret]
]);
var_dump($response->getStatusCode());
var_dump($response->getReasonPhrase());
What is changed is the payload that needs to be empty JSON object (but present) and the header name for the topic, it is apns-topic not apns-id. I also constructed the URL directly, not via the headers and used a pem file with private key included in it, not sure if those matter.
Maybe you should also check what you pass at the end of the URL, it is not the device_id, but the device_push_token.
NB: remember to always send the wallet push notification to the production apple endpoint, not the sandbox!
Related
Prerequisites
I have configured a custom domain for an API Gateway. The endpoint type is edge, as the API Gateway (RestApi) is edge.
I also issued a certificate through cdk. This is some of the code used:
const zone = route53.HostedZone.fromLookup(stack, 'Z0557019************', {
domainName: 'sub.example.com' // changed for SO post
})
const certificate = new DnsValidatedCertificate(stack, 'lws-api-certificate', {
domainName: 'mysub.sub.example.com', // changed for SO post
region: 'us-east-1',
hostedZone: zone
})
const api = new apigateway.RestApi(stack, 'legacy-wrapper-api', {
restApiName: 'My API',
domainName: {
domainName: 'mysub.sub.example.com',
certificate: certificate,
endpointType: EndpointType.EDGE
},
policy: apiResourcePolicy
})
new route53.ARecord(stack, 'ApiGatewayAliasRecord', {
zone: zone,
recordName: 'mysub',
target: route53.RecordTarget.fromAlias(new targets.ApiGateway(api))
})
So, I understand that a Cloudfront distribution is created. However, it is not listed in CloudFront.
In ApiGateway console:
What works
The custom domain was successfully created and applied and I am able to access my API gateway through mysub.sub.example.com.
What is not working
My issue is the following. I have clients which send a wrong Host Header. We can call our api fine when Host Header is mysub.sub.example.com. However, one client sends erroneously sub.another-example.com.
I know that this is a wrong header. But there is nothing we can do about this client sending the wrong header. Unfortunately!
What are my options?
switch to http
add foreign Host to allowed Hosts (certificate)?
Create some sort of proxy instance which allows incoming traffic from sub.another-example.com and redirect to
Regarding 1.
How can I allow http? I am seeing an option to set a minimum security level, but the minimum is TSL1.0. Can I even create a CloudFront distribution that accepts http? Again, in console I cannot see the distribution so I have to do it via CDK.
Regarding 2.
How can I do that, specifically in CDK?
Regarding 3.
Any creative ideas?
Help is much appreciated.
Additional resource:
A curl call to the custom domain with wrong header brings this:
$ curl --header "Authorization: Bearer 9c904d3##########################" --header "Host: sub.another-example.com" -v https://mysub.sub.example.com/v2.2/api/posts/list
* TCP_NODELAY set
* Connected to mysub.sub.example.com (18.66.###########) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=mysub.sub.example.com
* start date: May 27 00:00:00 2022 GMT
* expire date: Jun 25 23:59:59 2023 GMT
* subjectAltName: host "mysub.sub.example.com" matched cert's "mysub.sub.example.com"
* issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x5627934cd8c0)
> GET /v2.2/api/posts/list HTTP/2
> Host: sub.another-example.com <----------------- This is the problematic value
> user-agent: curl/7.68.0
> accept: */*
> authorization: Bearer 9c904d3##########################
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 403
< server: CloudFront
< date: Mon, 30 May 2022 11:21:50 GMT
< content-type: text/html
< content-length: 915
< x-cache: Error from cloudfront
< via: 1.1 f7d063##########################.cloudfront.net (CloudFront)
< x-amz-cf-pop: FRA56-P5
< x-amz-cf-id: _KTRiNK8z74PB4qCwS##################################################==
<
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>403 ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
Bad request.
We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
<BR clear="all">
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: _KTRiNK8z74PB4qCwS##################################################==
</PRE>
<ADDRESS>
</ADDRESS>
* Connection #0 to host mysub.sub.example.com left intact
</BODY></HTML>
As often when the questions are so specific I found a solution myself.
It is option 2! All with CDK.
Those are the steps:
As I mentioned the Cloudfront distribution created for the custom domain is hidden in console, so you need to create an new one.
you want an "Alternate domain name" with the value of "sub.another-example.com" to be appearing on the distributions settings
In order for that to work, you will need to create a certificate which also includes the foreign domain
for that certificate to validate you will need to put a CNAME to the DNS settings of that domain (so you need to be able to do that).
your certificate will not auto-validate by DNS of course! I found a hack for that which requires deploying two times.
Cloudfront distribution with alternate domain and cert
This is the final code.
import { CloudFrontToApiGateway } from '#aws-solutions-constructs/aws-cloudfront-apigateway'
let certificate
if (buildConfig.isFirstDeploy) {
// This is a helper for an otherwise manual step. Unfortunately, there is no better fix for foreign host certs.
// The first deploy will fail with message '*.another-example.com. is not permitted in zone *.sub.example.com
// However, you can then manually validate the *.another-example.com domain and use the ARN for following deploys
// https://stackoverflow.com/questions/58101817/cdk-dnsvalidatedcertificate-can-create-a-certificate-in-a-linked-aws-account-w
certificate = new DnsValidatedCertificate(stack, 'api-certificate', {
domainName: `mysub.sub.example.com`,
region: 'us-east-1', // required for edge https://docs.aws.amazon.com/acm/latest/userguide/acm-services.html
hostedZone: zone,
subjectAlternativeNames: ['*.another-example.com']
})
} else {
certificate = Certificate.fromCertificateArn(
stack,
'api-certificate',
'arn:aws:acm:us-east-1:#############:certificate/#################' // you only know that after first deploy, copy from console
)
}
const cloudfront = new CloudFrontToApiGateway(stack, 'MyCloudFrontDistribution', {
existingApiGatewayObj: api,
cloudFrontDistributionProps: {
certificate: certificate,
domainNames: [
`mysub.sub.example.com`,
'*.another-example.com'
]
}
})
I'm installing OpenVPN Access Server on a Google Cloud instance. Its webUI listens on port 943 using https. It has a self-signed certificate whose name doesn't match the server's hostname (10.150.0.2). I can't start an SSH tunnel. I'm looking for a way to troubleshoot the connection from the IAP service to my server.
The command I'm running is gcloud compute start-iap-tunnel vpn 943 --local-host-port=localhost:943 I receive the normal Testing if tunnel connection works message.
It errs out with ERROR: (gcloud.compute.start-iap-tunnel) While checking if a connection can be made: Error while connecting [4003: 'failed to connect to backend']. (Failed to connect to port 943)
If I add --log-http to the command invocation the relevant information follows (it looks like a normal req/resp cycle with a 200 that I assume is from my client to the IAP service):
Testing if tunnel connection works.
=======================
==== request start ====
uri: https://oauth2.googleapis.com/token
method: POST
== headers start ==
b'content-type': b'application/x-www-form-urlencoded'
b'user-agent': b'google-cloud-sdk gcloud/367.0.0 command/gcloud.compute.start-iap-tunnel invocation-id/db27de82264f47fcb63f6680afaa8327 environment/None environment-version/None interactive/False from-script/False python/3.7.9 term/xterm-256color (Macintosh; Intel Mac OS X 21.2.0)'
== headers end ==
== body start ==
Body redacted: Contains oauth token. Set log_http_redact_token property to false to print the body of this request.
== body end ==
==== request end ====
---- response start ----
status: 200
-- headers start --
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Encoding: gzip
Content-Type: application/json; charset=utf-8
Date: Fri, 24 Dec 2021 02:11:52 GMT
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Pragma: no-cache
Server: scaffolding on HTTPServer2
Transfer-Encoding: chunked
Vary: Origin, X-Origin, Referer
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 0
-- headers end --
-- body start --
Body redacted: Contains oauth token. Set log_http_redact_token property to false to print the body of this response.
-- body end --
total round trip time (request+response): 0.246 secs
---- response end ----
----------------------
ERROR: (gcloud.compute.start-iap-tunnel) While checking if a connection can be made: Error while connecting [4003: 'failed to connect to backend']. (Failed to connect to port 943)
To my knowledge this is the limit of easily accessible troubleshooting for start-tap-tunnel.
Moving on to the local machine we can connect to 10.150.0.2:943 before puking a la certificate.
root#viongier:/usr/local/openvpn_as# wget https://10.150.0.2:943
--2021-12-24 02:01:47-- https://10.150.0.2:943/
Connecting to 10.150.0.2:943... connected.
ERROR: The certificate of ‘10.150.0.2’ is not trusted.
ERROR: The certificate of ‘10.150.0.2’ doesn't have a known issuer.
The certificate's owner does not match hostname ‘10.150.0.2’
It seems to me that my client happily connects to the IAP service which fails to connect to my server. I would expect to see an IAP error if it was erring out because of the cert. The only thing I can think of to test this is by generating a certificate whose issuer google likes. (LetsEncrypt for example.)
This message means that the backend does not have a socket open in the listening state. Common reasons are that no service has been started or a firewall is blocking the port.
To allow the Identity Aware Proxy into your VPC, allow traffic from 35.235.240.0/20.
ERROR: (gcloud.compute.start-iap-tunnel) While checking if a
connection can be made: Error while connecting [4003: 'failed to
connect to backend']. (Failed to connect to port 943)
This error means that the certificate provided does not match the address that the connection is made to:
ERROR: The certificate of ‘10.150.0.2’ is not trusted. ERROR: The
certificate of ‘10.150.0.2’ doesn't have a known issuer. The
certificate's owner does not match hostname ‘10.150.0.2’
Some clients, such as wget support ignoring SSL certificate validation. For wget see the --no-check-certificate flag.
Once you solve that problem you will run into another set of problems:
Under normal circumstances, you can not use HTTPS with tunnels. Tunnels are a form of man in the middle. There are tricks that can be employed, none of them secure.
Commercial SSL certificates do not support IP addresses only public domain names. You would need to create your own self-signed certificate, which would not be trusted or do not validate the certificate.
The last issue is that HTTPS endpoints require encryption negotiation from the client party. The start-iap-tunnel command does not initiate encryption (TLS negotiation). This command also does not do any form of certificate exchange and that is why you do not see an IAP error about certificates. This command only transfers data between the tunnel endpoints.
In summary, you cannot use HTTPS with TCP / SSH tunnels without deploying tricks and/or disabling features which defeats the purpose of HTTPS.
Allow IAP traffic through the firewall allowed my external client to connect to the internal port 943 via an IAP tunnel.
Allowing port 943 from 35.235.240.0/20 solved my problem.
More information is available at the GCP IAP docs
I can't currently use the PayPal Sandbox to test my shopping-cart integrations. When i access the sandbox in a browser or via curl, all i get is connection errors.
Here's an example curl-session:
curl -v "https://api-3t.sandbox.paypal.com/nvp?user=test"
* Trying 173.0.82.83...
* TCP_NODELAY set
* Connected to api-3t.sandbox.paypal.com (173.0.82.83) port 443 (#0)
* TLS 1.2 connection using TLS_RSA_WITH_AES_256_CBC_SHA256
* Server certificate: api-3t.sandbox.paypal.com
* Server certificate: Symantec Class 3 Secure Server CA - G4
* Server certificate: VeriSign Class 3 Public Primary Certification Authority - G5
> GET /nvp?user=test HTTP/1.1
> Host: api-3t.sandbox.paypal.com
> User-Agent: curl/7.51.0
> Accept: */*
>
* SSLRead() return error -9806
* Curl_http_done: called premature == 1
* Closing connection 0
curl: (56) SSLRead() return error -9806
Any hints if this is a serverside issue or something i can work around?
Thanks!
Looks like the NVP/SOAP integration method of Paypal Express Checkout is deprecated as of January 1, 2017. The live URL (https://api-3t.paypal.com/nvp) seems to work for now, but this might be why the sandbox doesn't work anymore.
I don't exactly understand why, but using POST instead of GET when submitting data to the PayPal Sandbox solves the problem nicely. No more weird SSL-errors.
Found below answer to curl 56 error . Hope that could help work out of the problem.
curl (56) Recv failure
PHP CURL Error - curl: (56) Recv failure: Connection reset by peer
I was writing a very simple Golang script and use this library golang-jenkins to connect with our internal HTTPS server. But I face the following x509 cert issue and wasn't sure what to do with the x509 cert problem. Our team has zero access to Jenkins and would like to know what else we can do to dig more about the issue.
$ go run jenkins.go
2014/07/28 22:00:29 [] Get https://jenkins.mydomain.com/api/json: x509: certificate signed by unknown authority (possibly because of "x509: cannot verify signature: algorithm unimplemented" while trying to verify candidate authority certificate "MyDomain Internal Root CA")
using curl:
$ curl -v "https://jenkins.mydomain.com/api/json"
* Adding handle: conn: 0x7f8469004000
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7f8469004000) send_pipe: 1, recv_pipe: 0
* About to connect() to jenkins.mydomain.com port 443 (#0)
* Trying 10.38.8.70...
* Connected to jenkins.mydomain.com (10.38.8.70) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
* Server certificate: jenkins.mydomain.com
* Server certificate: MyDomain Server CA - 2014
* Server certificate: MyDomain Internal Root CA
> GET /api/json HTTP/1.1
> User-Agent: curl/7.30.0
> Host: jenkins.mydomain.com
> Accept: */*
>
< HTTP/1.1 200 OK
* Server nginx is not blacklisted
< Server: nginx
< Date: Tue, 29 Jul 2014 05:03:45 GMT
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: JSESSIONID.214ca1a4=1ry000odf815goiv7vl8tr627;Path=/;Secure
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< X-Jenkins: 1.554.3
< X-Jenkins-Session: c660ff91
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 is currently broken in Go, it will be supported in v1.4, the only workaround is to downgrade the TLS MaxVersion.
A quick look at golang-jenkins, it doesn't allow specifying the http.Client to use and just uses http.DefaultClient, the only ugly way to downgrade TLS's MaxVersion is to override http.DefaultClient.Transport.
You should be able to do something like this in func init() before you try to connect to anything:
cfg := &tls.Config{
MaxVersion: tls.VersionTLS11, // try tls.VersionTLS10 if this doesn't work
PreferServerCipherSuites: true,
}
http.DefaultClient.Transport = &http.Transport{
TLSClientConfig: cfg,
}
Keep in mind this will set the transport for anything that uses http.DefaultClient directly, like http.Get, however if you use your own instance, you will be fine.
Discussion about the bug: https://groups.google.com/forum/#!topic/golang-nuts/oK3EBAY2Uig
I wanted to try esmtp with smtp.hotpop.com
esend myfriend#yahoo.com "Test"
using http://www.rebol.org/view-script.r?script=esmtp.r and
http://www.rebol.org/view-script.r?script=esend.r
but it fails.
What's wrong ?
Here is all the information you should need to help you set up your mail client:
* Incoming/POP Server: pop.hotpop.com, port 110
* Alternate POP Server: pop.hotpop.com, port 1100
* Username: reboltutorial#HotPOP.com
* Outgoing/SMTP Server: smtp.hotpop.com, port 25*
* Email Address: reboltutorial#HotPOP.com
* Reply-To Address: reboltutorial#HotPOP.com (or any other email address you have)
* Leave Messages on server: false (some clients will instead have a "Delete messages from server" option, which should be set to true).
* Maximum Message Size: 500 KB (512000 bytes)
* Mailbox Size: 10 MB
* Mailbox Usage: 0.0% (0.0 KB)
*HotPOP's outgoing (SMTP) mail server requires authentication. The username and password are the same as the POP Server and website. Do not select "secure" password authentication.
Well, I couldn't get much of a response from this site .. and there are 100+ questions to answer to signup for their free service.
But esmtp is now built into the latest rebol binaries. no need to use one from the library.
so ...try the following
set-net [ reboltutorial#hotpop.com smtp.hotpop.com ]
trace/net on
send reboltutorial#hotpop.com "testing"
and see what error message comes up.
the protocol should ask you for your userid and password so that you can authenticate.