以上就是给各位分享AnIntroductiontoOpenSSLProgramming(PartI),同时本文还将给你拓展AnIntroductiontoProtocolOrientedProgram
以上就是给各位分享An Introduction to OpenSSL Programming (Part I),同时本文还将给你拓展An Introduction to Protocol Oriented Programming in Swift、Aspect-Oriented Programming : Aspect-Oriented Programming with the RealProxy Class、Coursera《Introduction to Recommender Systems》Program Assignment3 用户相似性计算、CSE105 - Introduction to Programming in Java等相关知识,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
本文目录一览:
An Introduction to OpenSSL Programming (Part I)
1
Introduction
The quickest and easiest way to secure a TCP-based network application is with SSL. If you’re
working in C, your best choice is probably to use OpenSSL, (the web site is at
http://www.openssl.org/). OpenSSL is a free (BSD-style license) implementation of
SSL/TLS based on Eric Young’s SSLeay package. Unfortunately, the documentation and sample
code distributed with OpenSSL leaves something to be desired. Where they exist, the manual
pages are pretty good, but they often miss the big picture, as manual pages are intended as a reference, not a tutorial.
We provide an introduction to OpenSSL programming. The OpenSSL API is vast and com-
plicated so we don’t attempt to provide anything like complete coverage. Rather, the idea is to
teach you enough to work effectively from the manual pages. In this article, the first of two, we
build a simple Web client and server pair that demonstrates the basic features of OpenSSL. In
the second article we introduce a number of advanced features, such as session resumption and
client authentication.
We assume that you’re already familiar with SSL and HTTP at least at a conceptual level. If
you’re not, a good place to start is with the RFCs (see the end of this article for references).
2
Source Code
For space reasons, this article only includes excerpts from the source code. The complete source
code is available in machine-readable format from the author’s web site at
http://www.rtfm.com/openssl-examples/
3
Our Programs
Our client is a simple HTTPS (see RFC 2818) client. It initiates an SSL connection to the server
and then transmits an HTTP request over that connection. It then waits for the response from the
server and prints it to the screen. This is a vastly simplified version of the functionality found in
programs like fetch and cURL.
The server program is a simple HTTPS server. It waits for TCP connections from clients.
When it accepts one it negotiates an SSL connection. Once the connection is negotiated, it reads
the client’s HTTP request. It then transmits the HTTP response to the client. Once the response
is transmitted it closes the connection.
3.1
Context Initialization
Our first task is to set up a context object (an
SSL_CTX). This context object is then used to create a new connection object for each new SSL connection. It is these connection objects which
are used to do SSL handshakes, reads, and writes.
This approach has two advantages. First, the context object allows many structures to be ini-
tialized only once, improving performance. In most applications, every SSL connection will use
This article is Copyright © 2001 Eric Rescorla. It may be redistributed for any purpose and without fee provided
that this notice is retained. An earlier version of this article first appeared in the September 2001 issue of Linux Journal.
the same keying material, certificate authority (CA) list, etc. Rather than reloading this material
for every connection, we simply load it into the context object at program startup. When we
wish to create a new connection, we can simply point that connection to the context object. The
second advantage of having a single context object is that it allows multiple SSL connections to
share data, such as the SSL session cache used for session resumption.
Context initialization consists of four primary tasks, all performed by the
initialize_ctx() function, shown in Figure 1.
SSL_CTX *initialize_ctx(keyfile,password)
char *keyfile;
char *password;
{
SSL_METHOD *meth;
SSL_CTX *ctx;
if(!bio_err){
/* Global system initialization*/
SSL_library_init();
SSL_load_error_strings();
/* An error write context */
bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
}
/* Set up a SIGPIPE handler */
signal(SIGPIPE,sigpipe_handle);
/* Create our context*/
meth=SSLv23_method();
ctx=SSL_CTX_new(meth);
/* Load our keys and certificates*/
if(!(SSL_CTX_use_certificate_chain_file(ctx, keyfile)))
berr_exit("Can’t read certificate file");
pass=password;
SSL_CTX_set_default_passwd_cb(ctx,password_cb);
if(!(SSL_CTX_use_PrivateKey_file(ctx, keyfile,SSL_FILETYPE_PEM)))
berr_exit("Can’t read key file");
/* Load the CAs we trust*/
if(!(SSL_CTX_load_verify_locations(ctx,CA_LIST,0)))
berr_exit("Ca’t read CA list");
#if (OPENSSL_VERSION_NUMBER < 0x0090600fL)
SSL_CTX_set_verify_depth(ctx,1);
#endif
return ctx;
}
Figure 1 initialize_ctx()
Initialize the library and create the context
Before OpenSSL can be used for anything, the library as a whole must be initialized. This is
accomplished with
SSL_library_init(), which primarily loads up the algorithms that
OpenSSL will be using. If we want good reporting of errors, we also need to load the error
strings using
SSL_load_error_strings(). Otherwise, we won’t be able to map
OpenSSL errors to strings.
We also create an object to be used as an error printing context. OpenSSL uses an abstraction called a BIO object for input and output. This allows the programmer to use the same functions for different kinds of I/O channels (sockets, terminal, memory buffers, etc.) merely by using different kinds of BIO objects. In this case we create a BIO object attached to stderr to be used for printing errors.
Load our own keys
If you’re writing server--or a client which is able to perform client authentication--you’ll need to
load your own public/private key pair and the associated certificate. The certificate is stored in
the clear and is loaded together with the CA certificates forming the certificate chain using
SSL_CTX_use_certificate_chain_file(). We use
SSL_CTX_use_PrivateKey_file() to load the private key. For security reasons, the private key is usually encrypted
under a password. If the key is encrypted, the password callback (set using
SSL_CTX_set_default_passwd_cb()) will be called to obtain the password.
Load root CA list
If you’re going to be authenticating the host you’re connected to OpenSSL needs to know what
certificate authorities (CAs) you trust. The
SSL_CTX_load_verify_locations() call is used to load the CAs.
Load Randomness
In order to have good security, SSL needs a good source of strong random numbers. In general,
it’s the responsibility of the application to supply some seed material for the random number
generator. However, OpenSSL automatically uses /dev/urandom to seed the RNG, if it is
available. Since /dev/urandom is standard on Linux, we don’t have to do anything for
this--which is convenient since gathering random numbers is tricky and easy to screw up. Note
that if you’re on a system other than Linux you may get an error at some point because the random number generator is unseeded. OpenSSL’s
rand(3) manual page provides more information.
4
The Client
Once the client has initialized the SSL context, it’s ready to connect to the server. OpenSSL
requires us to create a TCP connection between client and server on our own and then use the
TCP socket to create an SSL socket. For convenience we’ve isolated the creation of the TCP
connection to the tcp_connect() function (which is not shown here but is available in the
downloadable source).
Once the TCP connection has been created, we create an SSL object to handle the connec-
tion. This object needs to be attached to the socket. Note that that we don’t directly attach the
SSL object to the socket. Rather, we create a BIO object using the socket and then attach the
SSL object to the BIO.
This abstraction layer allows you to use OpenSSL over channels other than sockets, pro-
vided you have an appropriate BIO. For instance, one of the OpenSSL test programs connects
an SSL client and server purely through memory buffers. A more practical use would be to sup-
port some protocol that can’t be accessed via sockets. For instance, you could run SSL over a
serial line.
Handshake
The first step in an SSL connection is to perform the SSL handshake. The handshake authenti-
cates the server (and optionally the client) and establishes the keying material that will be used
to protect the rest of the traffic. The
SSL_connect() call is used to perform the SSL hand-
shake. Because we’re using blocking sockets,
SSL_connect() will not return until the hand-
shake is completed or an error has been detected.
SSL_connect() returns 1 for success and 0
or negative for an error. This call is shown in Figure 2.
/* Connect the TCP socket*/
sock=tcp_connect(host,port);
/* Connect the SSL socket */
ssl=SSL_new(ctx);
sbio=BIO_new_socket(sock,BIO_NOCLOSE);
SSL_set_bio(ssl,sbio,sbio);
if(SSL_connect(ssl)<=0)
berr_exit("SSL connect error");
if(require_server_auth)
check_cert(ssl,host);
Figure 2 connecting to the server
Server Authentication
When we initiate an SSL connection to a server, we need to check the server’s certificate chain.
OpenSSL does some of the checks for us but unfortunately some of the checks are application
specific and so we have to do those ourselves. The primary test that our sample application does
is to check the server identity. This check is performed by the
check_cert() function, shown
in Figure 3.
void check_cert(ssl,host)
SSL *ssl;
char *host;
{
X509 *peer;
char peer_CN[256];
if(SSL_get_verify_result(ssl)!=X509_V_OK)
berr_exit("Certificate doesn’t verify");
/*Check the cert chain. The chain length is automatically checked by OpenSSL when we set the verify depth in the ctx */
/*Check the common name*/
peer=SSL_get_peer_certificate(ssl);
X509_NAME_get_text_by_NID (X509_get_subject_name(peer),
NID_commonName, peer_CN, 256);
if(strcasecmp(peer_CN,host))
err_exit("Common name doesn’t match host name");
}
Figure 3 check_cert() function
Server Identity
Once you’ve established that the server’s certificate chain is valid, you need to verify that the
certificate you’re looking at matches the identity that we expect the server to have. In most
cases, this means that the server’s DNS name appears in the certificate, either in the Common
Name field of the Subject Name or in a certificate extension. Although each protocol has slightly
different rules for verifying the server’s identity, RFC 2818 contains the rules for HTTP over
SSL/TLS. Following RFC 2818 is generally a good idea unless you have some explicit reason to
do otherwise. to
Since most certificates still contain the domain name in Common Name rather than an
extension, we show only the Common Name check. We simply extract the server’s certificate
using
SSL_get_peer_certificate() and then compare the common name to the host
name we’re connecting to. If they don’t match, something is wrong and we exit.
Chain Length
Before version 0.9.5, OpenSSL was subject to a certificate extension attack. To see what this is,
consider the case where you a server authenticates with a certificate signed by Bob, as shown in
Figure 4. Bob isn’t one of your CAs but his certificate is signed by a CA you trust.
Root
CA
Bob
Server
Figure 4 An extended certificate chain
If you accept this certificate you’re likely going to be in a lot of trouble. The fact that the CA
signed Bob’s certificate means that the CA believes that it has verified Bob’s identity, not that
Bob can be trusted. If you know that you want to do business with Bob, that’s fine, but it’s not
very useful if you want to do business with Alice and Bob (who you’ve never heard of) is vouching for Alice.
Originally, the only way to protect yourself against this sort of attack was to restrict the
length of certificate chains so that you knew that the certificate you’re looking at was signed by
the CA. X.509 version 3 contains a way for a CA to label certain certificates as other CAs. This
permits a CA to have a single root that then certifies a bunch of subsidiary CAs.
Modern versions of OpenSSL (0.9.5 and later) check these extensions so you’re automati-
cally protected against extension attacks whether or not you check chain length. Versions prior
to 0.9.5 do not check the extensions at all, so you have to enforce the chain length if using an
older version. 0.9.5 has some problems with checking so if you’re using 0.9.5, you should probably upgrade. The #ifdef-ed code in initialize_ctx() provides chain length checking
with older versions. We use the
SSL_CTX_set_verify_depth() to force OpenSSL to
check the chain length. In summary, it’s highly advisable to upgrade to 0.9.6, particularly since
longer (but properly constructed) chains are becoming more popular.
When To Check Certicates
The code shown here allows the entire handshake to complete, whether or not the peer has a
valid certificate. It’s important to note that this is not the only way to check the server’s
certificate. Only after the handshake completes do we check the certificate and possibly terminate the connection. This approach has the advantage that it’s easy to implement but the disadvantage that if we don’t like the server’s certificate the server just sees a generic error rather than one indicating that the certificate was bad.
An alternative is to use the
SSL_CTX_set_verify() API call to have OpenSSL require
valid certificates during the handshake—if the server presents an invalid certificate the hand-
shake will fail and the server will receive an error indicating that it had a bad certificate. You can
also use
SSL_CTX_set_verify() to set a callback to be called during certificate checking,
allowing you to apply extra checks or permit certificates which OpenSSL might otherwise not
accept.
Request
We use the code shown in Figure 5 to write the HTTP request. For demonstration purposes, we
use a more-or-less hardwired HTTP request, found in the
REQUEST_TEMPLATE variable.
Because the machine we’re connecting to may change we do need to fill in the Host header.
This is done using the sprintf() in line 30. We then use SSL_write() to send the data to
the server.
SSL_write()as write(), except that we pass in the SSL object instead of the
file descriptor.
Experienced TCP programmers will notice that instead of looping around the write we
throw an error if the return value doesn’t equal the value we’re trying to write. In blocking
mode,
SSL_write() semantics are ’all-or-nothing’: the call won’t return until all the data is
written or an error occurs, whereas write() may only write part of the data.
Note: The
SSL_MODE
_ENABLE_PARTIAL_WRITE flag (not used here) enables partial
writes, in which case you’d need to loop.
Response
In old-style HTTP/1.0, the server transmits its response and then closes the connection. In later
versions, persistent connections that allow multiple sequential transactions on the same connec-
tion were introduced. For convenience and simplicity we will not use persistent connections. We
omit the header that allows them, causing the server to use a connection close to signal the end
of the response. Operationally, this means that we can keep reading until we get an end of file,
which simplifies matters considerably.
OpenSSL uses the
SSL_read() API call to read data, as shown in Figure 6. As with
read() we simply choose an appropriate sized buffer and pass it to SSL_read(). Note that
the buffer size isn’t really that important here. The semantics of SSL_read(), like the seman-
tics of read(), are that it returns the data available, even if it’s less than the requested amount.
On the other hand, if no data is available, then the call to read blocks.
The choice of
BUFSIZZ, then, is basically a performance tradeoff. The tradeoff is quite different here than when we’re simply reading from normal sockets. In that case, each call to read() requires a context switch into the kernel. Because context switches are expensive, programmers try to use large buffers to reduce them. However, when we’re using SSL the number of calls to read()—and hence context switches—is largely determined by the number of records the data was written in rather than the number of calls to SSL_read().
request_len=strlen(REQUEST_TEMPLATE)+strlen(host)+6;
if(!(request=(char *)malloc(request_len)))
err_exit("Couldn’t allocate request");
sprintf(request,REQUEST_TEMPLATE,host,port);
/* Find the exact request_len */
request_len=strlen(request);
r=SSL_write(ssl,request,request_len);
switch(SSL_get_error(ssl,r)){
case SSL_ERROR_NONE:
if(request_len!=r)
err_exit("Incomplete write!");
break;
default:
berr_exit("SSL write problem");
}
Figure 5 writing the HTTP request
For instance, if the client wrote a 1000-byte record and we call SSL_read() in chunks of 1
byte, then the first call to SSL_read() will result in the record being read
in and the rest of the calls will just read it out of the SSL buffer. Thus, the choice of buffer size
is less significant when we’re using SSL than with normal sockets.
Note that if the data were written in a series of small records, you might want to read
all of them at once with a single call to read(). OpenSSL provides a flag
SSL_CTRL_SET_READ_AHEAD that turns on this behavior.
while(1){
r=SSL_read(ssl,buf,BUFSIZZ);
switch(SSL_get_error(ssl,r)){
case SSL_ERROR_NONE:
len=r;
break;
case SSL_ERROR_ZERO_RETURN:
goto shutdown;
case SSL_ERROR_SYSCALL:
fprintf(stderr,"SSL Error: Premature close0);
goto done;
default:
berr_exit("SSL read problem");
}
fwrite(buf,1,len,stdout);
}
Figure 6 reading the response
Note the use of the switch on the return value of
SSL_get_error() in line 12. The con-
vention with normal sockets is that any negative number (typically −1) indicates failure and that
one then checks errno to determine what actually happened. Obviously errno won’t work
here since that only shows system errors and we’d like to be able to act on SSL errors. Also,
errno requires careful programming in order to be thread safe.
Instead of errno, OpenSSL provides the SSL_get_error() call. This call lets us
examine the return value and figure out whether an error occurred and what it was. If the return
value was positive, we’ve read some data and we simply write it to the screen. A real client
would of course parse the HTTP response and either display the data (e.g. a web page) or save it
to disk. However, none of this is interesting as far as OpenSSL is concerned so we don’t show
any of it.
If the return value was zero, this does not mean that there was no data available. In that case,
we would have blocked as discussed above. Rather, it means that the socket is closed and there
will never be any data available to read. Thus, we exit the loop.
Error Handling
If the return value was something negative then some kind of error occurred. There are two
kinds of errors we’re concerned with: ordinary errors and "premature closes". We use the
SSL_get_error() call to determine which kind of error we have. Error handling in our
client is pretty primitive so with most errors we simply call berr_exit() to print an error
message and exit. Premature closes have to be handled specially.
Closure
TCP uses a FIN segment to indicate that the sender has sent all of its data. SSL version 2 simply
allowed either side to send a TCP FIN to terminate the SSL connection. This allowed for a
"truncation attack": the attacker could make it appear that a message was shorter than it was
simply by forging a TCP FIN. Unless the victim had some other way of knowing what message
length to expect it would simply believe that it had received a shorter message.
In order to prevent this security problem, SSLv3 introduced a close_notify alert. The
close_notify is an SSL message (and therefore secured) but is not part of the data stream itself
and so is not seen by the application. No data may be transmitted after the close_notify is sent.
Thus, when SSL_read() returns 0 to indicate that the socket has been closed, this really
means that the close_notify has been received. If the client receives a FIN before receiving a
close_notify, SSL_read() will return with an error. This is called a "premature close".
A naive client might decide to report an error and exit whenever it received a premature
close. This is the behavior that is implied by the SSLv3 specification. Unfortunately, sending
premature closes is a rather common error, particularly common with clients. Thus, unless you
want to be reporting errors all the time you often have to ignore premature closes. Our code
splits the difference. It reports the premature close on stderr but doesn’t exit with an error.
Shutdown
If we read the response without any errors then we need to send our own close_notify to the
server. This is done using the SSL_shutdown() API call. We’ll cover SSL_shutdown()
more completely when we talk about the server but the general idea is simple: it returns 1 for a
complete shutdown, 0 for an incomplete shutdown, and -1 for an error. Since we’ve already
received the server’s close_notify, about the only thing that can go wrong is that we have trouble
sending our close_notify. Otherwise SSL_shutdown() will succeed (returning 1).
Cleanup
Finally, we need to destroy the various objects we’ve allocated. Since this program is about to
exit, freeing the objects automatically, this isn’t strictly necessary, but would be in a real program.
5
Server
Our web server is mainly a mirror of the client, but with a few twists. First, we fork() in order
to let the server handle multiple clients. Second, we use OpenSSL’s BIO APIs to read the
client’s request one line at a time, as well as to do buffered writes to the client. Finally, the
server closure sequence is more complicated.
Accept and Fork
On Linux, the simplest way to write a server that can handle multiple clients is to create a new
server process for each client that connects. We do that by calling fork() after accept()
returns. Each new process executes independently and just exits when it’s finished serving the
client. Although this approach can be quite slow on busy web servers it’s perfectly acceptable
here. The main server accept loop is shown in Figure 7.
while(1){
if((s=accept(sock,0,0))<0)
err_exit("Problem accepting");
if((pid=fork())){
close(s);
}
else {
sbio=BIO_new_socket(s,BIO_NOCLOSE);
ssl=SSL_new(ctx);
SSL_set_bio(ssl,sbio,sbio);
if((r=SSL_accept(ssl)<=0))
berr_exit("SSL accept error");
http_serve(ssl,s);
exit(0);
}
}
Figure 7 server accept loop
Server Accept
After forking and creating the SSL object, the server calls SSL_accept() which causes
OpenSSL to perform the server side of the SSL handshake. As with SSL_connect(),
because we’re using blocking sockets, SSL_accept() will block until the entire handshake
has completed. Thus, the only situation in which SSL_accept() will return is when the hand-
shake has completed or an error has been detected. SSL_accept() returns 1 for success and 0
or negative for error.
Buffered I/O
OpenSSL’s BIO objects are to some extent stackable. Thus, we can wrap an SSL object in a
BIO (the ssl_bio object) and then wrap that BIO in a buffered BIO object, as shown in Fig-
ure 8. This allows us to perform buffered reads and writes on the SSL connection by using the
BIO_* functions on the new io object. At this point you might ask: why is this good? Primarily,
it’s a matter of programming convenience: It lets the programmer work in natural units (lines
and characters) rather than SSL records.
13 io=BIO_new(BIO_f_buffer());
14 ssl_bio=BIO_new(BIO_f_ssl());
15 BIO_set_ssl(ssl_bio,ssl,BIO_CLOSE);
16 BIO_push(io,ssl_bio);
Figure 8 creating a buffered BIO
Request
An HTTP request consists of a request line followed by a bunch of header lines and an optional
body. The end of the header lines is indicated by a blank line (i.e., a pair of CRLFs, though
sometimes broken clients will send a pair of LFs instead). The most convenient way to read the
request line and headers is to read one line at a time until you see a blank line. We can do this
using the OpenSSL BIO_gets() call, as shown in Figure 9.
The BIO_gets() call behaves analogously to the stdio fgets() call. It takes an arbi-
trary size buffer and a length and reads a line from the SSL connection into that buffer. The
result is always null terminated (but includes the terminating LF). Thus, we simply read one line
at a time until we get a line which consists of simply a LF or a CRLF.
Because we use a fixed length buffer, it is possible though unlikely that we will get an over-
long line. In that event the long line will be split over two lines. In the (extremely unlikely) event
that the split happens right before the CRLF, the next line we read will consist only of the CRLF
from the previous line. In this case we’ll be fooled into thinking that the headers have finished
prematurely. A real Web server would check for this case but it’s not worth doing here. Note that
no matter what the incoming line length there’s no chance of a buffer overrun. All that can hap-
pen is that we’ll misparse the headers.
Note that we don’t really DO anything with the HTTP request. We just read it and discard it.
A real implementation would read the request line and the headers, figure out of there was a
body and read that too. However, none of these things show anything interesting about SSL so
they don’t add anything to this demonstration.
18
while(1){
19
r=BIO_gets(io,buf,BUFSIZZ-1);
20
21
switch(SSL_get_error(ssl,r)){
22
case SSL_ERROR_NONE:
23
len=r;
24 break;
25 default:
26
berr_exit("SSL read problem");
27
}
28
29
/* Look for the blank line that signals
30
the end of the HTTP headers */
31
if(!strcmp(buf,"0) ||!strcmp(buf,"0))
33
34
break;
}
Figure 9 reading the request
Response
The next step is to write the HTTP response and close the connection. Figure 10 shows this
code. Note that we’re using BIO_puts() instead of SSL_write(). This allows us to write
the response one line at a time but have the entire response written as a single SSL record. This
is important because the cost of preparing an SSL record for transmission (computing the
integrity check and encrypting it) is quite significant. Thus, it’s a good idea to make the records
as large as possible.
It’s worth noting a couple of subtleties about using this kind of buffered write:
1. You need to flush the buffer before you close. The SSL object has no knowledge that you’ve
layered a BIO on top of it, so if you destroy the SSL connection you’ll just leave the last
chunk of data sitting in the buffer. The BIO_flush() call in line 46 takes care of this.
2. By default, OpenSSL uses a 1024-byte buffer size for buffered BIOs. Because SSL records
can be up to 16K bytes long, using a 1024-byte buffer cause excessive fragmentation (and
hence lower performance.) You can use the BIO_ctrl() API to increase the buffer size.
if((r=BIO_puts
(io,"HTTP/1.0 200 OK\r\n"))<0)
err_exit("Write error");
if((r=BIO_puts
(io,"Server: EKRServer\r\n\r\n"))<0)
err_exit("Write error");
if((r=BIO_puts
43 (io,"Server test page\r\n"))<0)
44 err_exit("Write error");
45
46
47
if((r=BIO_flush(io))<0)
err_exit("Error flushing BIO");
Figure 10 writing the response
Shutdown
Once we’ve finished transmitting the response we need to send our close_notify. As before, this
is done using SSL_shutdown(). Unfortunately, things get a bit trickier when the server
closes first. Our first call to SSL_shutdown() sends the close_notify but doesn’t look for it on
the other side. Thus, it returns immediately but with a value of 0, indicating that the closure
sequence isn’t finished. It’s then the application’s responsibility to call SSL_shutdown()
again.
It’s possible to have two attitudes here:
1. We’ve seen all of the HTTP request that we care about. we’re not interested in anything else.
Hence, we don’t care whether the client sends a close_notify or not.
2. We strictly obey the protocol and expect others to as well. Thus, we require a close_notify.
If we have the first attitude then life is simple: We call SSL_shutdown() to send our
close_notify and then exit right away, regardless of whether the client has sent one or not. If we
take the second attitude (which our sample server does), then life is more complicated, because
clients often don’t behave correctly.
The first problem we face is that client’s often don’t send close_notifys all. In fact, some
clients close the connection as soon as they’ve read the entire HTTP response (some versions of
IE do this). When we send our close_notify, the other side may send a TCP RST segment, in
which case the program will catch a SIGPIPE. We install a dummy SIGPIPE handler in ini-
tialize_ctx() to protect against this problem.
The second problem we face is that the client may not send a close_notify immediately in
response to our close_notify. Some versions of Netscape require you to send a TCP FIN first.
Thus, we call shutdown(s,1) before we call SSL_shutdown() the second time. When
called with a "how" argument of 1, shutdown() sends a FIN but leaves the socket open for
reading. The code to do the server shutdown is shown in Figure 11 (see next page).
6
What’s Missing
In this article, we’ve only scratched the surface of the issues involved with using OpenSSL.
Here’s a (non-exhaustive) list of additional issues.
Better Certificate Checking
A more sophisticated approach to checking server certificates against the server hostname is to
use the X.509 subjectAltName extension. In order to make this check, you would need to extract
this extension from the certificate and then check it against the hostname. Additionally, it would
be nice to be able to check host names against wildcarded names in certificates. We don’t show
how to do this either.
51 r=SSL_shutdown(ssl);
52 if(!r){
53
/* If we called SSL_shutdown() first then
54 we always get return value of ’0’. In
55 this case, try again, but first send a
56 TCP FIN to trigger the other side’s
57
close_notify*/
58
shutdown(s,1);
59
60
r=SSL_shutdown(ssl);
}
61
62
switch(r){
63
case 1:
64
break; /* Success */
65 case 0:
66 case -1:
67 default:
68
69
berr_exit("Shutdown failed");
}
Figure 11 calling SSL_shutdown()
Better Error Handling
Note that these applications handle errors simply by exiting with an error. A real application
would, of course, be able to recognize errors and signal them to the user or some audit log rather
than just exiting.
6.1
Coming Soon
In the second part, we’ll be discussing a number of advanced OpenSSL features, including...
Session Resumption
SSL handshakes are expensive but SSL provides a feature called session resumption that allows
you to bypass the full handshake for a peer you’ve communicated with before.
Multiplexed and Non-blocking I/O
We used blocking sockets for all of our reads and writes. This means that while the application
is waiting for data from the peer it’s completely stalled. This wouldn’t be acceptable in a real
GUI application like a browser. Instead, you need to use the select() call to multiplex
between SSL and other sources of I/O.
Client Authentication
Server authentication occurs as a part of almost every SSL connection. However, SSL also offers
certificate-based client authentication, at the server’s request.
6.2
External Resources
Parts of this article were adapted from my book "SSL and TLS: Designing and Building Secure
Systems", Addison-Wesley 2000. "SSL and TLS" offers a comprehensive guide to the SSL pro-
tocol and its applications. See http://www.rtfm.com/sslbook for more information.
Machine readable source code for the programs presented here can be downloaded from the
author’s web site at: http://www.rtfm.com/openssl-examples/. The source code is
available under a BSD-style license.
You can get OpenSSL from http://www.openssl.org/. The docs are online here as well.
The relevant specifications are at:
SSLv2: http://www.netscape.com/eng/security/SSL_2.html
SSLv3: http://home.netscape.com/eng/ssl3/index.html
TLS (RFC 2246): http://www.ietf.org/rfc/rfc2246.txt
HTTPS (RFC 2818): http://www.ietf.org/rfc/rfc2818.txt
6.3
Acknowledgements
Thanks to Lisa Dusseault, Steve Henson, Lutz Jaenicke, and Ben Laurie for help with OpenSSL
and review of this article.

An Introduction to Protocol Oriented Programming in Swift
swift面向协议编程的根本原因在于值类型的存在;面向对象必须要有引用类型的支持;
Protocol Oriented approach was introduced to resolve some issues in programming and it also differs in varIoUs scenarios when compared to Object-Oriented programming. So let’s dive into the topic.
What is Protocol Oriented Programming?
Protocols basically serve as a blueprint like classes rather than a fully functional types for methods, properties, and other requirements. This is done to perform a piece of functionality and behaves like an interface and tells what to implement. It is a powerful feature of Swift Language. Apple tells us:
“Don’t Start with the Class, Start with the Protocol”
Why We Need POP?
When we design any software system, then we figure out the general requirements that satisfy the given system. We, even model the relationship b/w the UI elements such as buttons, view, images etc. for which we generally start with superclass and model the relationships using inheritance.
In Swift, as we have the concept of POP so, we can even start with protocols and can model the relationships as protocol implementations. In the protocol oriented approach, we model our system with a protocol, rely on the concepts like:
- Protocol Extensions
- Protocol Inheritance
- Protocol Composition
In Swift, we use structs, enums, and tuples rather than working only with classes since, Value Semantics are preferred over Reference Types.
Also, there Could be varIoUs cases where OOP is not the best solution to implement. Let’s check and figure out the drawbacks in Object-Oriented concept. We kNow that Inheritance is one of the most important concepts in OOP but, inheritance doesn’t work for value types and modern languages like Swift prohibits to support the feature of multiple inheritances due to complexities and value types is the first citizen of Swift. So, POP does a great job by providing the ability to add multiple abilities to the class, struct, and enum with protocols and extensions that supports multiple implementations while we code.

Other benefits with Protocol implementations are:
- Swift checks whether the requirements of the protocol are full-filled or not for the classes we are implementing at compile-time, so, this helps us to find out if there were any issues or bugs in code even before we ran our program.
- Also, protocols bring more abstraction mechanism than classes do in Swift.
- We’re not restricted to only use classes since any type, including value types, can implement a protocol.
- A type can implement multiple protocols.
- We can create as many protocols as we need.
Before I talk about POP in detail and how to use and implement it, we must understand the basics right, so let us focus on Swift Types first. Here is the diagrammatic representation of Swift Types that we have.

Well, here I am interested in the behavior of Classes and Structure, one belongs to the reference type and other to value type and observe how objects behave through an example.

And, this is really important to understand and why is it so? If you have a very complex hierarchy and you set something in one part of the code, it should not have any wrong consequences in the other part. So, the lesson is:
- Classes use reference i.e if you set something to other it is not a copy instead it is a reference.
- Whereas, in value type such as structures, passes things as a copy, not as a reference.
Conclusion
Apple, always recommends going with the value type while we program in Swift. Structures are preferable when we have a small copy of data and it is much safer than having multiple references to the same objects in our code. The concept becomes more important when we talk about variable and passing their value. In Swift, we work in a multi-threaded environment and if we have copies of variable then, we don’t need to worry about them in the other place where value may get change. So, using structure is advised by Apple and Protocol-Oriented Programming serves better abstraction with structures.
Using Protocols and it’s extensions features, we can really ignore/avoid for making a huge superclass and then inheriting functionality from there. So, Hope it is Now clear to you what is POP and why Apple use this.
Note: This does not mean that we don’t use Class, there are some situations where classes are the only option left for our implementation.
In the other part of this article, we will see how to implement and use protocols, protocol extensions, Generics with the protocol.
https://www.technotification.com/2018/08/protocol-oriented-programming-swift.html

Aspect-Oriented Programming : Aspect-Oriented Programming with the RealProxy Class
Aspect-Oriented Programming : Aspect-Oriented Programming with the RealProxy Class
A well-architected application has separate layers so different concerns don’t interact more than needed. Imagine you’re designing a loosely coupled and maintainable application,but in the middle of the development,you see some requirements that might not fit well in the architecture,such as:
- The application must have an authentication system,used before any query or update.
- The data must be validated before it’s written to the database.
- The application must have auditing and logging for sensible operations.
- The application must maintain a debugging log to check if operations are OK.
- Some operations must have their performance measured to see if they’re in the desired range.
Any of these requirements need a lot of work and,more than that,code duplication. You have to add the same code in many parts of the system,which goes against the “don’t repeat yourself” (DRY) principle and makes maintenance more difficult. Any requirement change causes a massive change in the program. When I have to add something like that in my applications,I think,“Why can’t the compiler add this repeated code in multiple places for me?” or,“I wish I had some option to ‘Add logging to this method.’”
The good news is that something like that does exist: aspect-oriented programming (AOP). It separates general code from aspects that cross the boundaries of an object or a layer. For example,the application log isn’t tied to any application layer. It applies to the whole program and should be present everywhere. That’s called a crosscutting concern.
AOP is,according to Wikipedia,“a programming paradigm that aims to increase modularity by allowing the separation of crosscutting concerns.” It deals with functionality that occurs in multiple parts of the system and separates it from the core of the application,thus improving separation of concerns while avoiding duplication of code and coupling.
In this article,I’ll explain the basics of AOP and then detail how to make it easier by using a dynamic proxy via the Microsoft .NET Framework class RealProxy.

Coursera《Introduction to Recommender Systems》Program Assignment3 用户相似性计算
在Coursera上跟了 明尼苏达大学《Introduction to Recommender Systems》的课,
课程的编程作业 老师提供的模板是JAVA,由于主要是用C++,对于JAVA只是简单的翻过一本书,
编程作业 都是用python 来自己搭建整个框架
由于我是用Python写作业 所以会遇到这些问题
发出来 是希望给 使用其他编程语言的同学 提个醒
Program Assignment 3的作业 做出的结果更 样例输出 不一样,debug一遍代码觉得没有问题;
后来根据 论坛上的反馈 一点点找问题 发现是我 计算 user 之间的相似性 跟模板不一样
但是 根据课堂上的公式、wiki资料等 我的计算公式不存在问题;
后来我故意改成 我认为“错误”的公式 发现跟模板输出一致。。。顿感大窘啊
(后来我又仔细看了下视频,助教给出了他那么做的解释,见后文。)
具体讨论 我发在了 论坛上 不过 反应平平:
The answer of PA3 is wrong! the error occurred in the templete!
我使用 助教 的公式 PA3 刷了满分

我贴一下 Python代码 应该不“违法”
__author__ = ''LiFeiteng''
# -*- coding: utf-8 -*-
import numpy as np
class UserUserRec:
def __init__(self):
self.U = 0
self.M = 0
self.user_dict = {}
self.movie_dict = {}
self.movie_title = {}
self.user_ratings = np.matrix([])
def GetratingData(self,ratings_file):
for line in open(ratings_file):
user,movie,rating = line.split(",")
if not self.user_dict.has_key(user):
self.user_dict[user] = self.U
self.U += 1
if not self.movie_dict.has_key(movie):
self.movie_dict[movie] = self.M
self.M += 1
print self.U,self.M
self.user_ratings = np.matrix(np.zeros([self.U,self.M]))
for line in open("ratings.csv","r"):
user,")
self.user_ratings[self.user_dict[user],self.movie_dict[movie]] = np.double(rating)
def GetMovieTitles(self,movie_titles_file):
for line in open(movie_titles_file):
movie,title = line.split(",")
#delete ''\n''
self.movie_title[movie] = title[:-1]
def CosineUserSim(self,user1,user2):
# 我觉得这里使用的公式是不对的
user_rat = self.user_ratings[user1,:].copy()
u1 = user_rat - np.mean(user_rat[user_rat>0.0])
u1 = np.array(u1)*np.array(np.where(user_rat>0,1,0))
user_rat = self.user_ratings[user2,:].copy()
u2 = user_rat - np.mean(user_rat[user_rat>0.0])
u2 = np.array(u2)*np.array(np.where(user_rat>0,0))
if (np.linalg.norm(u1[0,:])*np.linalg.norm(u2[0,:])) == 0:
sim = 0.0
else: #问题出在这里的norm上,norm会计算user1 user2 不共同评分的项
sim = np.dot(u1[0,:],u2[0,:])/(np.linalg.norm(u1[0,:]))
return np.double(sim)
def Moviescore4User(self,user,movie):
#以下省略 N 行
return score4movie
# end of class UserUserRec
#### PA3
user_user_rec = UserUserRec()
user_user_rec.GetratingData("ratings.csv")
user_user_rec.GetMovieTitles("movie-titles.csv")
user_user_rec.Moviescore4User(''1024'',''77'')
outfile = open("outfile.txt","w")
for line in open("input.txt"):
user,movie = line.split(":")
movie = str(int(movie))
score = user_user_rec.Moviescore4User(user,movie)
str1 = ",".join([user,format(score,".4f"),user_user_rec.movie_title[movie]])
outfile.write(str1)
outfile.close()
正如 论坛里面 我的讨论, CosineUserSim(user1,user2)的计算方法 是存在问题的。
here
the cosine between the users’ mean-centered rating vectors
is same with the Pearson correlation
=====================================================
看下这个帖子,二楼是助教
Pearson vs. Cosine Similarity
助教的解释是:均值化的cosine相似性 跟 Pearson相关系数 不同——就是除以 norm的问题上
我觉得 可能是实验证实 或 理论分析 这样做比较好!或许我教学视频看得不够仔细呢。。。
又回过头 看了下视频 助教给出了这么做的解释:Video 4.3 24:00分起+
算是对 原始用户相关性的一个改进,因为如果是使用相同评分项会导致“平凡情况”,如果两个用户只有一个评分项相同 那么sim=1
这样做有些“鲁莽”,他们只有一个相同点而已;改进的方法还有很多其他,下文只是其中一种。
是我太 鲁莽了。。。

CSE105 - Introduction to Programming in Java
CSE105 - Introduction to Programming in Java
CSE105
Joe Lewis and Andrew Abel– October 2019
CSE105 CW3 2019
Due date: 7/12/2019 - Saturday 7th December at 18:00 - 30% of final mark
Task
Create a Java application which displays a pictograph for a given data set. You
should create a relevant dataset, choose appropriate images, and design and
code an application to display this information. You should also write a short
report.
Pictograph
A pictograph displays data using pictures. Every pictograph has a title, label, key,
and some pictures or symbols. A simple example is shown here:
Further information and examples can be found at
https://vc012.k12.sd.us/Graphs/picto1.html
You should use your graphics and programming knowledge to create your own,
given your chosen dataset. Your design and colour should be unique to you, and
you should pay attention to OOP principles as taught this semester. You may reuse
and re-purpose code and classes developed and used (by you) in the Labs.
Dataset
Your dataset must be related to the number of endangered animals living in a
number of countries/regions. You should research and choose/create your own
dataset.
• Possible animals: lions, elephants, tigers.
• The data sets will contain from 5 to 10 countries (inclusive).
• The data will be contained in a plain text .txt file in CSV format (See
appendix for example).
CSE105 - Introduction to Programming in Java
CSE105
Joe Lewis and Andrew Abel– October 2019
Task Requirements:
1. Pictograph Representation ( 55%)
May be landscape or portrait
Minimum
• Should use an appropriate graphic (picture) to represent the animals
• Must state the number of animals represented by 1 graphic icon (key)
• Must make the total number of animals easy to read (not just by adding
up the number of icons)
• Display the information on screen accurately
Excellent
• Use fractional icons for fractional quantities (if 1 icon = 1000 lions, ½ an
icon = 500 lions)
• Be fully labelled with title, and axis labels
• Scale appropriately to work on different screen sizes; re-scale as the
window is made bigger or smaller.
• Reads csv file
2. Graphical Styling ( 20%)
• Use colour, font editing, drawing, and other visual enhancements to make
the layout clear and attractive, and enhance readability
3. Design Document and Code Quality ( 25%)
• Submit a design document. This should be submitted as a pdf or
Microsoft Word document.
• Should contain a class diagram (created yourself, not autogenerated in
Netbeans)
• Should contain a small description of each class, written in good quality
English
• Code should follow clear conventions for variable names, comments,
indentation, and should be readable
4. Core Task Requirements (required to reach 40%)
• The submitted file should be a valid Netbeans project folder, including all
resources. Test it carefully before submitting.
• The project must compile and run in Netbeans with no further
configuration and debugging
• Submission instructions must be followed exactly. Marks will be
deducted for not following the instructions.
• The assignment is English language, and must be entirely in English with
no Chinese characters
• The zip file must be in .zip format, not .rar
• If the above steps are not followed, then the assignment will not pass
CSE105 - Introduction to Programming in Java
CSE105
Joe Lewis and Andrew Abel– October 2019
Notes
• All of this can and should be achieved using the Java resources covered in
the lectures so far this semester, mainly the drawing and painting
properties of the Graphics object.
• You may use code and resources from the lectures and labs this semester.
• Do not attempt to construct a complete Swing or JavaFX GUI package
using multiple components, containers, widgets, Layout managers etc.
• Search the internet and look at professionally produces examples to get
ideas for your design. Simple and clear is best.
• The design should be your own. Shared designs with friends will be
considered plagiarism.
Submission
You must submit your work electronically on the CSE105 ICE page before 7
December 2019 at 18:00 (7/12/2019). A dropbox will be made available the
week before.
You must submit:
• One design document (a Word or PDF document) with a simple UML
diagram detailing the classes and the relationships between them, and a
small description of the classes.
• One .txt file for each .java class file. These documents must NOT be in a
CSE105 留学生作业代做
ZIP archive. The file name must be the class name. Each file must have
your name/student number in a comment at the top.
• One ZIP archive of your entire Netbeans project folder. Make sure this
contains ALL the resources your application needs to run.
• If your program does not compile and run from this zip file only, you
cannot pass (See Core Task Requirements). The zip file name must start
with your student number.
This assignment is individual work. Plagiarism (e.g. copying materials from
other sources without proper acknowledgement) is a serious academic
offence. Plagiarism and collusion will not be tolerated and will be dealt with in
accordance with the University Code of Practice on Academic Integrity. Individual
students may be invited to explain parts of their code in person, and if they fail to
demonstrate an understanding of the code, no credit will be given for that part of
the code.
CSE105 - Introduction to Programming in Java
CSE105
Joe Lewis and Andrew Abel– October 2019
Appendix, Example data set:
File name Animal_Data.txt
File content: title, label, and number
如有需要,请加 QQ:99515681 或微信:codehelp
我们今天的关于An Introduction to OpenSSL Programming (Part I)的分享已经告一段落,感谢您的关注,如果您想了解更多关于An Introduction to Protocol Oriented Programming in Swift、Aspect-Oriented Programming : Aspect-Oriented Programming with the RealProxy Class、Coursera《Introduction to Recommender Systems》Program Assignment3 用户相似性计算、CSE105 - Introduction to Programming in Java的相关信息,请在本站查询。